From 119c5aafc36f47b91a62fa782e44cc35ae422d07 Mon Sep 17 00:00:00 2001 From: hobbes1069 Date: Tue, 18 Jul 2017 14:11:40 +0000 Subject: [PATCH] Branch and tag freedv 1.2.2 and codec2 0.7. git-svn-id: https://svn.code.sf.net/p/freetel/code@3307 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/CMakeLists.txt | 2 +- codec2/branches/0.7/CMakeLists.txt | 244 + codec2/branches/0.7/COPYING | 502 + codec2/branches/0.7/INSTALL | 52 + codec2/branches/0.7/README | 157 + codec2/branches/0.7/README_fdmdv.txt | 201 + codec2/branches/0.7/README_fsk.txt | 82 + .../0.7/cmake/GetDependencies.cmake.in | 24 + codec2/branches/0.7/cmake/config.h.in | 23 + codec2/branches/0.7/codec2.pc.in | 10 + codec2/branches/0.7/debian/changelog | 5 + codec2/branches/0.7/debian/codec2.doc-base.EX | 20 + codec2/branches/0.7/debian/codec2.install | 1 + codec2/branches/0.7/debian/codec21.dirs | 1 + codec2/branches/0.7/debian/codec21.install | 1 + codec2/branches/0.7/debian/compat | 1 + codec2/branches/0.7/debian/control | 36 + codec2/branches/0.7/debian/copyright | 38 + codec2/branches/0.7/debian/docs | 6 + codec2/branches/0.7/debian/libcodec2-dev.dirs | 2 + .../branches/0.7/debian/libcodec2-dev.install | 1 + codec2/branches/0.7/debian/libcodec2.install | 1 + codec2/branches/0.7/debian/rules | 24 + codec2/branches/0.7/debian/source/format | 1 + .../0.7/octave/2400ab_frame_design.ods | Bin 0 -> 19194 bytes .../branches/0.7/octave/H2064_516_sparse.mat | 7231 ++ codec2/branches/0.7/octave/HRA_112_112.txt | 119 + codec2/branches/0.7/octave/HRA_112_56.txt | 63 + codec2/branches/0.7/octave/HRA_56_28.txt | 35 + codec2/branches/0.7/octave/HRA_56_56.txt | 63 + codec2/branches/0.7/octave/Mat2Hrows.m | 26 + codec2/branches/0.7/octave/adc_plot_spec.m | 51 + codec2/branches/0.7/octave/adc_sfdr_ut.m | 34 + codec2/branches/0.7/octave/adcres.m | 56 + codec2/branches/0.7/octave/autotest.m | 114 + codec2/branches/0.7/octave/av_imp.m | 43 + codec2/branches/0.7/octave/bandpasssampling.m | 34 + codec2/branches/0.7/octave/bfq19ssa.m | 83 + codec2/branches/0.7/octave/bpf.m | 31 + codec2/branches/0.7/octave/bpsk.m | 284 + codec2/branches/0.7/octave/c2wideband_batch.m | 316 + codec2/branches/0.7/octave/c2wideband_const.m | 25 + codec2/branches/0.7/octave/c2wideband_fbf.m | 92 + codec2/branches/0.7/octave/cbphase.m | 98 + codec2/branches/0.7/octave/cellmodem.m | 137 + codec2/branches/0.7/octave/ciccomp.m | 70 + codec2/branches/0.7/octave/cma.m | 114 + codec2/branches/0.7/octave/cml.patch | 31 + codec2/branches/0.7/octave/codec2_demo.m | 108 + codec2/branches/0.7/octave/cohpsk.m | 992 + .../branches/0.7/octave/cohpsk_demod_plot.m | 159 + .../0.7/octave/cohpsk_frame_design.ods | Bin 0 -> 49734 bytes codec2/branches/0.7/octave/cohpsk_plots.m | 141 + codec2/branches/0.7/octave/crc16.m | 55 + codec2/branches/0.7/octave/cspec.m | 54 + codec2/branches/0.7/octave/dacres.m | 165 + codec2/branches/0.7/octave/df_mixer.m | 272 + codec2/branches/0.7/octave/diff_codec.m | 96 + codec2/branches/0.7/octave/doppler_spread.m | 37 + .../branches/0.7/octave/doppler_spread_ut.m | 51 + codec2/branches/0.7/octave/estsnr.m | 65 + codec2/branches/0.7/octave/fdmdv.m | 1164 + codec2/branches/0.7/octave/fdmdv_demod.m | 353 + codec2/branches/0.7/octave/fdmdv_demod_c.m | 132 + codec2/branches/0.7/octave/fdmdv_demod_coh.m | 253 + codec2/branches/0.7/octave/fdmdv_mod.m | 32 + codec2/branches/0.7/octave/fdmdv_sweep.m | 30 + codec2/branches/0.7/octave/fdmdv_ut.m | 352 + codec2/branches/0.7/octave/fdmdv_ut_coh.m | 341 + .../branches/0.7/octave/fdmdv_ut_freq_off.m | 489 + codec2/branches/0.7/octave/fm.m | 469 + .../0.7/octave/fm_radio_filt_model.txt | 8 + codec2/branches/0.7/octave/fmfsk.m | 346 + codec2/branches/0.7/octave/fsk.m | 251 + codec2/branches/0.7/octave/fsk4.m | 540 + codec2/branches/0.7/octave/fsk_basic.m | 60 + codec2/branches/0.7/octave/fsk_cont_phase.m | 85 + codec2/branches/0.7/octave/fsk_eme.m | 377 + codec2/branches/0.7/octave/fsk_horus.m | 803 + codec2/branches/0.7/octave/fsk_horus_2fsk.m | 979 + codec2/branches/0.7/octave/fsk_horus_stream.m | 227 + codec2/branches/0.7/octave/fsk_lib.m | 476 + codec2/branches/0.7/octave/fskdemodgui.py | 189 + codec2/branches/0.7/octave/fuzzy_gray.m | 586 + .../branches/0.7/octave/gen_complex_short.m | 18 + codec2/branches/0.7/octave/gen_rn_coeffs.m | 40 + codec2/branches/0.7/octave/glottal.m | 29 + codec2/branches/0.7/octave/gmsk.m | 1021 + codec2/branches/0.7/octave/gp_interleaver.m | 46 + codec2/branches/0.7/octave/hackrf_dc.m | 26 + codec2/branches/0.7/octave/hackrf_twotone.m | 24 + codec2/branches/0.7/octave/hackrf_uc.m | 47 + codec2/branches/0.7/octave/hf_modem_curves.m | 272 + codec2/branches/0.7/octave/hf_sim.m | 78 + codec2/branches/0.7/octave/hfper.m | 57 + .../branches/0.7/octave/horus_high_speed.bin | Bin 0 -> 2760 bytes codec2/branches/0.7/octave/horus_msg.txt | 1 + .../0.7/octave/horus_payload_rtty.txt | 1 + .../0.7/octave/horus_tx_bits_binary.txt | 1 + codec2/branches/0.7/octave/hp_filt.m | 12 + codec2/branches/0.7/octave/impulse_noise.m | 122 + codec2/branches/0.7/octave/kmeans2.m | 198 + codec2/branches/0.7/octave/kmeans_tests.m | 765 + codec2/branches/0.7/octave/ldpc.m | 143 + codec2/branches/0.7/octave/ldpc_fsk_lib.m | 269 + codec2/branches/0.7/octave/ldpc_gen_h_file.m | 72 + codec2/branches/0.7/octave/ldpc_qpsk.m | 458 + codec2/branches/0.7/octave/ldpc_short.m | 558 + codec2/branches/0.7/octave/ldpcdec.m | 300 + codec2/branches/0.7/octave/ldpcenc.m | 125 + codec2/branches/0.7/octave/ldpcut.m | 221 + codec2/branches/0.7/octave/linreg.m | 35 + codec2/branches/0.7/octave/load_comp.m | 9 + codec2/branches/0.7/octave/load_hackrf.m | 11 + codec2/branches/0.7/octave/load_raw.m | 8 + codec2/branches/0.7/octave/lpcauto.m | 116 + codec2/branches/0.7/octave/lpcpf.m | 46 + codec2/branches/0.7/octave/lsp.m | 54 + codec2/branches/0.7/octave/lsp_pdf.m | 91 + codec2/branches/0.7/octave/lspvar.m | 57 + codec2/branches/0.7/octave/lspwarp.m | 40 + codec2/branches/0.7/octave/mag_to_phase.m | 62 + codec2/branches/0.7/octave/make_hilb.m | 51 + codec2/branches/0.7/octave/make_ssbfilt.m | 36 + codec2/branches/0.7/octave/mancyfsk.m | 500 + codec2/branches/0.7/octave/melstats.m | 49 + codec2/branches/0.7/octave/melvq.m | 168 + codec2/branches/0.7/octave/mfsk.m | 199 + codec2/branches/0.7/octave/newamp.m | 1691 + codec2/branches/0.7/octave/newamp1_batch.m | 1384 + codec2/branches/0.7/octave/newamp1_compare.m | 56 + codec2/branches/0.7/octave/newamp1_fbf.m | 178 + codec2/branches/0.7/octave/newamp_batch.m | 112 + codec2/branches/0.7/octave/newamp_fbf.m | 207 + codec2/branches/0.7/octave/nf_from_gr.m | 113 + codec2/branches/0.7/octave/ofdm_dev.m | 997 + codec2/branches/0.7/octave/ofdm_lib.m | 456 + codec2/branches/0.7/octave/ofdm_load_const.m | 46 + codec2/branches/0.7/octave/ofdm_rs.m | 795 + codec2/branches/0.7/octave/ofdm_rx.m | 295 + codec2/branches/0.7/octave/ofdm_tx.m | 189 + codec2/branches/0.7/octave/oqpsk.m | 521 + codec2/branches/0.7/octave/phase.m | 56 + codec2/branches/0.7/octave/phase2.m | 57 + codec2/branches/0.7/octave/phasesecord.m | 47 + codec2/branches/0.7/octave/pitch_test.m | 39 + codec2/branches/0.7/octave/pl.m | 45 + codec2/branches/0.7/octave/pl2.m | 44 + codec2/branches/0.7/octave/plamp.m | 197 + codec2/branches/0.7/octave/plinterp.m | 11 + codec2/branches/0.7/octave/pllpcpf.m | 150 + codec2/branches/0.7/octave/pllsp.m | 46 + codec2/branches/0.7/octave/pllspdt.m | 27 + codec2/branches/0.7/octave/plnlp.m | 134 + codec2/branches/0.7/octave/plot_specgram.m | 30 + codec2/branches/0.7/octave/plphase.m | 198 + codec2/branches/0.7/octave/plpitch.m | 36 + codec2/branches/0.7/octave/plppe.m | 65 + codec2/branches/0.7/octave/plsub.m | 35 + codec2/branches/0.7/octave/plvoicing.m | 89 + codec2/branches/0.7/octave/png.m | 25 + codec2/branches/0.7/octave/postfilter.m | 24 + codec2/branches/0.7/octave/pulse.m | 37 + codec2/branches/0.7/octave/qpsk.m | 140 + codec2/branches/0.7/octave/rfdesign.m | 77 + codec2/branches/0.7/octave/s_param_rf.m | 206 + .../branches/0.7/octave/sample_clock_offset.m | 21 + .../branches/0.7/octave/save_array_c_header.m | 14 + codec2/branches/0.7/octave/save_raw.m | 7 + codec2/branches/0.7/octave/sd.m | 170 + codec2/branches/0.7/octave/spec.m | 86 + codec2/branches/0.7/octave/tcohpsk.m | 753 + codec2/branches/0.7/octave/telem_upload.py | 157 + codec2/branches/0.7/octave/test_cohpsk.m | 563 + codec2/branches/0.7/octave/test_cohpsk_ch.m | 21 + codec2/branches/0.7/octave/test_dqpsk.m | 394 + codec2/branches/0.7/octave/test_dqpsk2.m | 465 + codec2/branches/0.7/octave/test_dsss.m | 410 + codec2/branches/0.7/octave/test_dsss_pilot.m | 437 + codec2/branches/0.7/octave/test_fec.m | 406 + codec2/branches/0.7/octave/test_foff.m | 402 + codec2/branches/0.7/octave/test_ftrack.m | 197 + .../branches/0.7/octave/test_ldpc_fsk_lib.m | 851 + codec2/branches/0.7/octave/test_ml.m | 361 + codec2/branches/0.7/octave/test_pilot.m | 388 + codec2/branches/0.7/octave/test_qpsk.m | 516 + codec2/branches/0.7/octave/test_qpsk2.m | 641 + codec2/branches/0.7/octave/test_qpsk3.m | 957 + codec2/branches/0.7/octave/tfdmdv.m | 306 + codec2/branches/0.7/octave/tfmfsk.m | 497 + codec2/branches/0.7/octave/tfsk.m | 630 + codec2/branches/0.7/octave/tfsk_2400a.m | 648 + codec2/branches/0.7/octave/tget_spec.m | 49 + codec2/branches/0.7/octave/tlinreg.m | 14 + codec2/branches/0.7/octave/tnewamp1.m | 237 + codec2/branches/0.7/octave/tofdm.m | 159 + codec2/branches/0.7/octave/tpapr.m | 35 + codec2/branches/0.7/octave/tqpsk.m | 230 + codec2/branches/0.7/octave/trellis.m | 523 + codec2/branches/0.7/octave/twomixer.m | 38 + codec2/branches/0.7/octave/twotone.m | 52 + codec2/branches/0.7/octave/twotone1.m | 76 + codec2/branches/0.7/octave/tximage.m | 40 + codec2/branches/0.7/octave/undersample.m | 26 + codec2/branches/0.7/octave/vhf_pa.m | 111 + codec2/branches/0.7/octave/vq | 10247 +++ codec2/branches/0.7/octave/vq_pager.m | 47 + codec2/branches/0.7/octave/xormixer.m | 37 + codec2/branches/0.7/octave/yafsk.m | 664 + codec2/branches/0.7/raw/b0067.raw | Bin 0 -> 58482 bytes codec2/branches/0.7/raw/cq_ref.raw | Bin 0 -> 143828 bytes codec2/branches/0.7/raw/cross.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/cross_melp2400.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/f2400.raw | Bin 0 -> 27680 bytes codec2/branches/0.7/raw/forig.raw | Bin 0 -> 25224 bytes codec2/branches/0.7/raw/forig_ambe2000.raw | Bin 0 -> 32000 bytes codec2/branches/0.7/raw/forig_g729a.raw | Bin 0 -> 25120 bytes codec2/branches/0.7/raw/forig_gsm13k.raw | Bin 0 -> 25280 bytes codec2/branches/0.7/raw/forig_speex_8k.raw | Bin 0 -> 25280 bytes codec2/branches/0.7/raw/g3plx.raw | Bin 0 -> 91286 bytes codec2/branches/0.7/raw/hts.raw | Bin 0 -> 384000 bytes codec2/branches/0.7/raw/hts1.raw | Bin 0 -> 96000 bytes codec2/branches/0.7/raw/hts1a.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts1a_ambe2000.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts1a_g729a.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts1a_gsm13k.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts1a_melp.raw | Bin 0 -> 47880 bytes codec2/branches/0.7/raw/hts1a_speex_8k.raw | Bin 0 -> 47956 bytes codec2/branches/0.7/raw/hts2.raw | Bin 0 -> 96000 bytes codec2/branches/0.7/raw/hts2a.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts2a_ambe2000.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts2a_g729a.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts2a_gsm13k.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/hts2a_melp.raw | Bin 0 -> 47880 bytes codec2/branches/0.7/raw/hts2a_speex_8k.raw | Bin 0 -> 47780 bytes codec2/branches/0.7/raw/k6hx.raw | Bin 0 -> 166814 bytes codec2/branches/0.7/raw/kristoff.raw | Bin 0 -> 80000 bytes codec2/branches/0.7/raw/m2400.raw | Bin 0 -> 33624 bytes codec2/branches/0.7/raw/mmt1.raw | Bin 0 -> 64000 bytes codec2/branches/0.7/raw/mmt1_ambe2000.raw | Bin 0 -> 64000 bytes codec2/branches/0.7/raw/mmt1_g729a.raw | Bin 0 -> 64000 bytes codec2/branches/0.7/raw/mmt1_gsm13k.raw | Bin 0 -> 64000 bytes codec2/branches/0.7/raw/mmt1_speex_8k.raw | Bin 0 -> 64000 bytes codec2/branches/0.7/raw/morig.raw | Bin 0 -> 32056 bytes codec2/branches/0.7/raw/morig_ambe2000.raw | Bin 0 -> 48000 bytes codec2/branches/0.7/raw/morig_g729a.raw | Bin 0 -> 32000 bytes codec2/branches/0.7/raw/morig_gsm13k.raw | Bin 0 -> 32320 bytes codec2/branches/0.7/raw/morig_speex_8k.raw | Bin 0 -> 32056 bytes codec2/branches/0.7/raw/sine1k_2Hz_spread.raw | Bin 0 -> 962560 bytes .../0.7/raw/sine1k_2ms_delay_2Hz_spread.raw | Bin 0 -> 962560 bytes codec2/branches/0.7/raw/ve9qrp.raw | Bin 0 -> 1799168 bytes codec2/branches/0.7/raw/ve9qrp_10s.raw | Bin 0 -> 160000 bytes codec2/branches/0.7/raw/vk5qi.raw | Bin 0 -> 216716 bytes codec2/branches/0.7/script/menu.sh | 80 + codec2/branches/0.7/script/playraw.sh | 6 + codec2/branches/0.7/script/raw2wav.sh | 3 + codec2/branches/0.7/script/separate_all.sh | 13 + codec2/branches/0.7/script/wav2raw.sh | 3 + codec2/branches/0.7/src/CMakeLists.txt | 349 + codec2/branches/0.7/src/H2064_516_sparse.h | 31 + codec2/branches/0.7/src/HRA_112_112.h | 29 + codec2/branches/0.7/src/_kiss_fft_guts.h | 164 + codec2/branches/0.7/src/ampexp.c | 1095 + codec2/branches/0.7/src/ampexp.h | 39 + codec2/branches/0.7/src/bpf.h | 106 + codec2/branches/0.7/src/bpfb.h | 105 + codec2/branches/0.7/src/c2dec.c | 344 + codec2/branches/0.7/src/c2demo.c | 101 + codec2/branches/0.7/src/c2enc.c | 151 + codec2/branches/0.7/src/c2sim.c | 1003 + codec2/branches/0.7/src/codebook.c | 245 + codec2/branches/0.7/src/codebook/dlsp1.txt | 35 + codec2/branches/0.7/src/codebook/dlsp10.txt | 35 + codec2/branches/0.7/src/codebook/dlsp2.txt | 35 + codec2/branches/0.7/src/codebook/dlsp3.txt | 35 + codec2/branches/0.7/src/codebook/dlsp4.txt | 35 + codec2/branches/0.7/src/codebook/dlsp5.txt | 35 + codec2/branches/0.7/src/codebook/dlsp6.txt | 35 + codec2/branches/0.7/src/codebook/dlsp7.txt | 35 + codec2/branches/0.7/src/codebook/dlsp8.txt | 35 + codec2/branches/0.7/src/codebook/dlsp9.txt | 35 + codec2/branches/0.7/src/codebook/gecb.txt | 257 + codec2/branches/0.7/src/codebook/lsp1.txt | 17 + codec2/branches/0.7/src/codebook/lsp10.txt | 6 + codec2/branches/0.7/src/codebook/lsp2.txt | 17 + codec2/branches/0.7/src/codebook/lsp3.txt | 17 + codec2/branches/0.7/src/codebook/lsp4.txt | 17 + codec2/branches/0.7/src/codebook/lsp5.txt | 19 + codec2/branches/0.7/src/codebook/lsp6.txt | 19 + codec2/branches/0.7/src/codebook/lsp7.txt | 19 + codec2/branches/0.7/src/codebook/lsp8.txt | 11 + codec2/branches/0.7/src/codebook/lsp8910.txt | 65 + codec2/branches/0.7/src/codebook/lsp9.txt | 11 + codec2/branches/0.7/src/codebook/lspdt.txt | 1025 + .../branches/0.7/src/codebook/lspdt1-10.txt | 513 + codec2/branches/0.7/src/codebook/lspdt1.txt | 9 + codec2/branches/0.7/src/codebook/lspdt10.txt | 3 + codec2/branches/0.7/src/codebook/lspdt2.txt | 9 + codec2/branches/0.7/src/codebook/lspdt3.txt | 5 + codec2/branches/0.7/src/codebook/lspdt4.txt | 5 + codec2/branches/0.7/src/codebook/lspdt5.txt | 5 + codec2/branches/0.7/src/codebook/lspdt6.txt | 5 + codec2/branches/0.7/src/codebook/lspdt7.txt | 3 + codec2/branches/0.7/src/codebook/lspdt8.txt | 3 + codec2/branches/0.7/src/codebook/lspdt9.txt | 3 + codec2/branches/0.7/src/codebook/lspjvm1.txt | 513 + codec2/branches/0.7/src/codebook/lspjvm2.txt | 513 + codec2/branches/0.7/src/codebook/lspjvm3.txt | 513 + .../branches/0.7/src/codebook/lspmelvq1.txt | 65 + .../branches/0.7/src/codebook/lspmelvq2.txt | 65 + .../branches/0.7/src/codebook/lspmelvq3.txt | 65 + .../branches/0.7/src/codebook/lspres_bw1.txt | 5 + .../branches/0.7/src/codebook/lspres_bw2.txt | 10 + .../0.7/src/codebook/lspres_centre1.txt | 9 + .../0.7/src/codebook/lspres_centre2.txt | 10 + .../branches/0.7/src/codebook/lspvqanssi1.txt | 257 + .../branches/0.7/src/codebook/lspvqanssi2.txt | 129 + .../branches/0.7/src/codebook/lspvqanssi3.txt | 65 + .../branches/0.7/src/codebook/lspvqanssi4.txt | 65 + .../branches/0.7/src/codebook/lspvqexp1.txt | 2049 + .../branches/0.7/src/codebook/lspvqexp2.txt | 2049 + .../branches/0.7/src/codebook/lspvqexp3.txt | 2049 + codec2/branches/0.7/src/codebook/mel1.txt | 9 + codec2/branches/0.7/src/codebook/mel2.txt | 5 + codec2/branches/0.7/src/codebook/mel3.txt | 17 + codec2/branches/0.7/src/codebook/mel4.txt | 9 + codec2/branches/0.7/src/codebook/mel5.txt | 9 + codec2/branches/0.7/src/codebook/mel6.txt | 6 + .../0.7/src/codebook/newamp1_energy_q.txt | 17 + .../branches/0.7/src/codebook/train_120_1.txt | 513 + .../branches/0.7/src/codebook/train_120_2.txt | 513 + codec2/branches/0.7/src/codebookd.c | 433 + codec2/branches/0.7/src/codebookdt.c | 153 + codec2/branches/0.7/src/codebookge.c | 279 + codec2/branches/0.7/src/codebookjvm.c | 1579 + codec2/branches/0.7/src/codebooknewamp1.c | 1057 + .../branches/0.7/src/codebooknewamp1_energy.c | 39 + codec2/branches/0.7/src/codebookres.c | 97 + codec2/branches/0.7/src/codebookvq.c | 4223 ++ codec2/branches/0.7/src/codec2.c | 2269 + codec2/branches/0.7/src/codec2.h | 69 + codec2/branches/0.7/src/codec2_cohpsk.h | 68 + codec2/branches/0.7/src/codec2_fdmdv.h | 113 + codec2/branches/0.7/src/codec2_fft.c | 155 + codec2/branches/0.7/src/codec2_fft.h | 110 + codec2/branches/0.7/src/codec2_fifo.h | 60 + codec2/branches/0.7/src/codec2_fm.h | 53 + codec2/branches/0.7/src/codec2_internal.h | 86 + codec2/branches/0.7/src/codec2_ofdm.h | 69 + codec2/branches/0.7/src/cohpsk.c | 1303 + codec2/branches/0.7/src/cohpsk_ch.c | 341 + codec2/branches/0.7/src/cohpsk_defs.h | 9 + codec2/branches/0.7/src/cohpsk_demod.c | 227 + .../branches/0.7/src/cohpsk_get_test_bits.c | 87 + codec2/branches/0.7/src/cohpsk_internal.h | 124 + codec2/branches/0.7/src/cohpsk_mod.c | 123 + .../branches/0.7/src/cohpsk_put_test_bits.c | 109 + codec2/branches/0.7/src/comp.h | 38 + codec2/branches/0.7/src/comp_prim.h | 141 + codec2/branches/0.7/src/defines.h | 113 + codec2/branches/0.7/src/drs232.c | 235 + codec2/branches/0.7/src/drs232_ldpc.c | 285 + codec2/branches/0.7/src/dump.c | 674 + codec2/branches/0.7/src/dump.h | 82 + codec2/branches/0.7/src/fdmdv.c | 1990 + codec2/branches/0.7/src/fdmdv_channel.c | 104 + codec2/branches/0.7/src/fdmdv_demod.c | 246 + codec2/branches/0.7/src/fdmdv_get_test_bits.c | 124 + codec2/branches/0.7/src/fdmdv_interleave.c | 164 + codec2/branches/0.7/src/fdmdv_internal.h | 192 + codec2/branches/0.7/src/fdmdv_mod.c | 163 + codec2/branches/0.7/src/fdmdv_put_test_bits.c | 169 + codec2/branches/0.7/src/fec_dec.c | 307 + codec2/branches/0.7/src/fec_enc.c | 312 + codec2/branches/0.7/src/fifo.c | 143 + codec2/branches/0.7/src/fm.c | 290 + codec2/branches/0.7/src/fm_demod.c | 115 + codec2/branches/0.7/src/fm_fir_coeff.h | 413 + codec2/branches/0.7/src/fmfsk.c | 376 + codec2/branches/0.7/src/fmfsk.h | 110 + codec2/branches/0.7/src/fmfsk_demod.c | 144 + codec2/branches/0.7/src/fmfsk_mod.c | 99 + codec2/branches/0.7/src/fq20.sh | 8 + codec2/branches/0.7/src/freedv_api.c | 1782 + codec2/branches/0.7/src/freedv_api.h | 142 + codec2/branches/0.7/src/freedv_api_internal.h | 241 + codec2/branches/0.7/src/freedv_data_channel.c | 312 + codec2/branches/0.7/src/freedv_data_channel.h | 70 + codec2/branches/0.7/src/freedv_rx.c | 261 + codec2/branches/0.7/src/freedv_tx.c | 243 + codec2/branches/0.7/src/freedv_vhf_framing.c | 831 + codec2/branches/0.7/src/freedv_vhf_framing.h | 93 + codec2/branches/0.7/src/fsk.c | 1105 + codec2/branches/0.7/src/fsk.h | 190 + codec2/branches/0.7/src/fsk_demod.c | 296 + codec2/branches/0.7/src/fsk_get_test_bits.c | 90 + codec2/branches/0.7/src/fsk_mod.c | 108 + codec2/branches/0.7/src/fsk_put_test_bits.c | 104 + codec2/branches/0.7/src/generate_codebook.c | 179 + codec2/branches/0.7/src/golay23.c | 311 + codec2/branches/0.7/src/golay23.h | 44 + codec2/branches/0.7/src/golaydectable.h | 2052 + codec2/branches/0.7/src/golayenctable.h | 4100 ++ codec2/branches/0.7/src/hanning.h | 644 + codec2/branches/0.7/src/horus_l2.c | 1177 + codec2/branches/0.7/src/horus_l2.h | 23 + codec2/branches/0.7/src/ht_coeff.h | 107 + codec2/branches/0.7/src/insert_errors.c | 120 + codec2/branches/0.7/src/interp.c | 331 + codec2/branches/0.7/src/interp.h | 45 + codec2/branches/0.7/src/kiss_fft.c | 408 + codec2/branches/0.7/src/kiss_fft.h | 124 + codec2/branches/0.7/src/kiss_fftr.c | 154 + codec2/branches/0.7/src/kiss_fftr.h | 46 + codec2/branches/0.7/src/ldpc_dec.c | 245 + codec2/branches/0.7/src/ldpc_enc.c | 153 + codec2/branches/0.7/src/linreg.c | 106 + codec2/branches/0.7/src/linreg.h | 35 + codec2/branches/0.7/src/listensim.sh | 9 + codec2/branches/0.7/src/lpc.c | 306 + codec2/branches/0.7/src/lpc.h | 43 + codec2/branches/0.7/src/lsp.c | 321 + codec2/branches/0.7/src/lsp.h | 37 + codec2/branches/0.7/src/machdep.h | 52 + codec2/branches/0.7/src/mbest.c | 142 + codec2/branches/0.7/src/mbest.h | 58 + codec2/branches/0.7/src/modem_probe.c | 240 + codec2/branches/0.7/src/modem_probe.h | 115 + codec2/branches/0.7/src/modem_stats.c | 111 + codec2/branches/0.7/src/modem_stats.h | 75 + codec2/branches/0.7/src/mpdecode_core.c | 731 + codec2/branches/0.7/src/mpdecode_core.h | 93 + codec2/branches/0.7/src/newamp1.c | 607 + codec2/branches/0.7/src/newamp1.h | 80 + codec2/branches/0.7/src/nlp.c | 702 + codec2/branches/0.7/src/nlp.h | 38 + codec2/branches/0.7/src/noise_samples.h | 60006 ++++++++++++++++ codec2/branches/0.7/src/octave.c | 143 + codec2/branches/0.7/src/octave.h | 39 + codec2/branches/0.7/src/ofdm.c | 781 + codec2/branches/0.7/src/ofdm_internal.h | 103 + codec2/branches/0.7/src/os.h | 53 + codec2/branches/0.7/src/pack.c | 140 + codec2/branches/0.7/src/phase.c | 289 + codec2/branches/0.7/src/phase.h | 39 + codec2/branches/0.7/src/phaseexp.c | 1461 + codec2/branches/0.7/src/phaseexp.h | 39 + codec2/branches/0.7/src/pilot_coeff.h | 41 + codec2/branches/0.7/src/pilots_coh.h | 6 + codec2/branches/0.7/src/postfilter.c | 142 + codec2/branches/0.7/src/postfilter.h | 33 + codec2/branches/0.7/src/quantise.c | 2055 + codec2/branches/0.7/src/quantise.h | 141 + codec2/branches/0.7/src/resample.c | 160 + codec2/branches/0.7/src/rn.h | 964 + codec2/branches/0.7/src/rn_coh.h | 604 + codec2/branches/0.7/src/rxdec_coeff.h | 35 + codec2/branches/0.7/src/sim.sh | 22 + codec2/branches/0.7/src/sine.c | 687 + codec2/branches/0.7/src/sine.h | 49 + codec2/branches/0.7/src/ssbfilt_coeff.h | 107 + codec2/branches/0.7/src/tdma.h | 85 + codec2/branches/0.7/src/test_bits.h | 164 + codec2/branches/0.7/src/test_bits_coh.h | 564 + codec2/branches/0.7/src/test_bits_ofdm.h | 229 + codec2/branches/0.7/src/varicode.c | 486 + codec2/branches/0.7/src/varicode.h | 52 + codec2/branches/0.7/src/varicode_table.h | 338 + codec2/branches/0.7/src/vhf_deframe_c2.c | 113 + codec2/branches/0.7/src/vhf_frame_c2.c | 106 + codec2/branches/0.7/stm32/MENU.txt | 45 + codec2/branches/0.7/stm32/Makefile | 919 + codec2/branches/0.7/stm32/README.txt | 133 + codec2/branches/0.7/stm32/inc/debugblinky.h | 35 + codec2/branches/0.7/stm32/inc/gdb_stdio.h | 47 + codec2/branches/0.7/stm32/inc/iir_duc.h | 37 + codec2/branches/0.7/stm32/inc/iir_tuner.h | 36 + codec2/branches/0.7/stm32/inc/menu.h | 92 + codec2/branches/0.7/stm32/inc/morse.h | 65 + codec2/branches/0.7/stm32/inc/new_i2c.h | 107 + codec2/branches/0.7/stm32/inc/sfx.h | 63 + codec2/branches/0.7/stm32/inc/si53xx.h | 315 + codec2/branches/0.7/stm32/inc/sine.h | 48 + .../0.7/stm32/inc/sm1000_leds_switches.h | 86 + codec2/branches/0.7/stm32/inc/sounds.h | 38 + codec2/branches/0.7/stm32/inc/stm32f4_adc.h | 46 + .../0.7/stm32/inc/stm32f4_adc_tuner.h | 40 + codec2/branches/0.7/stm32/inc/stm32f4_dac.h | 46 + .../branches/0.7/stm32/inc/stm32f4_dacduc.h | 42 + .../branches/0.7/stm32/inc/stm32f4_usb_vcp.h | 24 + codec2/branches/0.7/stm32/inc/stm32f4_vrom.h | 70 + .../branches/0.7/stm32/inc/stm32f4xx_conf.h | 94 + .../branches/0.7/stm32/inc/tm_stm32f4_gpio.h | 429 + .../0.7/stm32/inc/tm_stm32f4_mco_output.h | 188 + codec2/branches/0.7/stm32/inc/tone.h | 84 + codec2/branches/0.7/stm32/inc/tot.h | 115 + codec2/branches/0.7/stm32/src/adc_rec.c | 76 + codec2/branches/0.7/stm32/src/adc_rec_usb.c | 85 + codec2/branches/0.7/stm32/src/adc_sd.c | 75 + codec2/branches/0.7/stm32/src/adc_sfdr_ut.c | 89 + codec2/branches/0.7/stm32/src/adcdac_ut.c | 70 + .../branches/0.7/stm32/src/codec2_profile.c | 181 + codec2/branches/0.7/stm32/src/dac_it.c | 205 + codec2/branches/0.7/stm32/src/dac_play.c | 63 + codec2/branches/0.7/stm32/src/dac_ut.c | 57 + codec2/branches/0.7/stm32/src/dac_ut_fast.c | 37 + codec2/branches/0.7/stm32/src/debugblinky.c | 57 + codec2/branches/0.7/stm32/src/fast_dac_ut.c | 116 + codec2/branches/0.7/stm32/src/fdmdv_dump_rt.c | 154 + codec2/branches/0.7/stm32/src/fdmdv_profile.c | 149 + codec2/branches/0.7/stm32/src/fft_test.c | 176 + .../0.7/stm32/src/freedv_rx_profile.c | 136 + .../0.7/stm32/src/freedv_tx_profile.c | 90 + codec2/branches/0.7/stm32/src/gdb_stdio.c | 125 + codec2/branches/0.7/stm32/src/iir_duc.c | 371 + codec2/branches/0.7/stm32/src/iir_tuner.c | 325 + codec2/branches/0.7/stm32/src/init.c | 10 + codec2/branches/0.7/stm32/src/mco_ut.c | 39 + codec2/branches/0.7/stm32/src/menu.c | 98 + codec2/branches/0.7/stm32/src/morse.c | 175 + codec2/branches/0.7/stm32/src/new_i2c.c | 430 + codec2/branches/0.7/stm32/src/power_ut.c | 135 + codec2/branches/0.7/stm32/src/sfx.c | 67 + codec2/branches/0.7/stm32/src/si5351_ut.c | 45 + codec2/branches/0.7/stm32/src/si53xx.c | 856 + codec2/branches/0.7/stm32/src/sine.c | 648 + .../0.7/stm32/src/sm1000_leds_switches.c | 229 + .../0.7/stm32/src/sm1000_leds_switches_ut.c | 41 + codec2/branches/0.7/stm32/src/sm1000_main.c | 1249 + .../branches/0.7/stm32/src/sm2000_adc_dump.c | 113 + codec2/branches/0.7/stm32/src/sm2000_rxdemo.c | 153 + codec2/branches/0.7/stm32/src/sm2000_stw.c | 169 + codec2/branches/0.7/stm32/src/sounds.c | 62 + .../0.7/stm32/src/startup_stm32f4xx.s | 512 + codec2/branches/0.7/stm32/src/stm32f4_adc.c | 281 + .../0.7/stm32/src/stm32f4_adc_tuner.c | 289 + codec2/branches/0.7/stm32/src/stm32f4_dac.c | 406 + .../branches/0.7/stm32/src/stm32f4_dacduc.c | 416 + .../branches/0.7/stm32/src/stm32f4_dacloduc.c | 276 + .../branches/0.7/stm32/src/stm32f4_machdep.c | 86 + codec2/branches/0.7/stm32/src/stm32f4_pwm.c | 236 + .../branches/0.7/stm32/src/stm32f4_usb_vcp.c | 90 + codec2/branches/0.7/stm32/src/stm32f4_vrom.c | 724 + .../branches/0.7/stm32/src/system_stm32f4xx.c | 584 + codec2/branches/0.7/stm32/src/timer_ut.c | 179 + .../branches/0.7/stm32/src/tm_stm32f4_gpio.c | 238 + .../0.7/stm32/src/tm_stm32f4_mco_output.c | 128 + codec2/branches/0.7/stm32/src/tone.c | 151 + codec2/branches/0.7/stm32/src/tot.c | 90 + codec2/branches/0.7/stm32/src/tuner_ut.c | 122 + codec2/branches/0.7/stm32/src/usb_vcp_ut.c | 96 + codec2/branches/0.7/stm32/src/usb_vsp_ut.c | 192 + codec2/branches/0.7/stm32/stlink/elfsym.c | 145 + codec2/branches/0.7/stm32/stlink/elfsym.h | 14 + codec2/branches/0.7/stm32/stlink/stlink.patch | 428 + codec2/branches/0.7/stm32/stm32_flash.ld | 142 + codec2/branches/0.7/stm32/stm32_ram.ld | 116 + codec2/branches/0.7/stm32/usb_conf/usb_bsp.c | 337 + codec2/branches/0.7/stm32/usb_conf/usb_bsp.h | 97 + codec2/branches/0.7/stm32/usb_conf/usb_conf.h | 287 + .../branches/0.7/stm32/usb_conf/usbd_conf.h | 97 + .../branches/0.7/stm32/usb_conf/usbd_desc.c | 324 + .../branches/0.7/stm32/usb_conf/usbd_desc.h | 114 + codec2/branches/0.7/stm32/usb_conf/usbd_usr.c | 126 + .../0.7/stm32/usb_lib/cdc/usbd_cdc_core.c | 811 + .../0.7/stm32/usb_lib/cdc/usbd_cdc_core.h | 137 + .../0.7/stm32/usb_lib/cdc/usbd_cdc_vcp.c | 280 + .../0.7/stm32/usb_lib/cdc/usbd_cdc_vcp.h | 68 + .../0.7/stm32/usb_lib/core/usbd_core.c | 476 + .../0.7/stm32/usb_lib/core/usbd_core.h | 114 + .../0.7/stm32/usb_lib/core/usbd_def.h | 149 + .../0.7/stm32/usb_lib/core/usbd_ioreq.c | 237 + .../0.7/stm32/usb_lib/core/usbd_ioreq.h | 115 + .../0.7/stm32/usb_lib/core/usbd_req.c | 868 + .../0.7/stm32/usb_lib/core/usbd_req.h | 102 + .../0.7/stm32/usb_lib/core/usbd_usr.h | 135 + .../branches/0.7/stm32/usb_lib/otg/usb_core.c | 2187 + .../branches/0.7/stm32/usb_lib/otg/usb_core.h | 408 + .../branches/0.7/stm32/usb_lib/otg/usb_dcd.c | 475 + .../branches/0.7/stm32/usb_lib/otg/usb_dcd.h | 158 + .../0.7/stm32/usb_lib/otg/usb_dcd_int.c | 889 + .../0.7/stm32/usb_lib/otg/usb_dcd_int.h | 121 + .../0.7/stm32/usb_lib/otg/usb_defines.h | 244 + .../branches/0.7/stm32/usb_lib/otg/usb_regs.h | 1206 + codec2/branches/0.7/unittest/CMakeLists.txt | 97 + codec2/branches/0.7/unittest/Makefile.am | 114 + codec2/branches/0.7/unittest/Makefile.in | 1090 + codec2/branches/0.7/unittest/README | 43 + codec2/branches/0.7/unittest/c2validate.c | 103 + codec2/branches/0.7/unittest/c2validate.h | 33 + .../0.7/unittest/create_interleaver.c | 48 + codec2/branches/0.7/unittest/de.c | 59 + codec2/branches/0.7/unittest/dvdongle2.c | 385 + codec2/branches/0.7/unittest/extract.c | 126 + codec2/branches/0.7/unittest/fdmdv_mem.c | 63 + codec2/branches/0.7/unittest/ge_train.c | 299 + codec2/branches/0.7/unittest/genampdata.c | 104 + codec2/branches/0.7/unittest/genlsp.c | 183 + codec2/branches/0.7/unittest/genphdata.c | 93 + codec2/branches/0.7/unittest/genres.c | 99 + codec2/branches/0.7/unittest/hts1a.h | 8002 +++ codec2/branches/0.7/unittest/hts1a_1300.h | 8002 +++ codec2/branches/0.7/unittest/lsp1.txt | 16 + codec2/branches/0.7/unittest/lsp10.txt | 5 + codec2/branches/0.7/unittest/lsp2.txt | 16 + codec2/branches/0.7/unittest/lsp3.txt | 16 + codec2/branches/0.7/unittest/lsp4.txt | 16 + codec2/branches/0.7/unittest/lsp45678910.txt | 4097 ++ codec2/branches/0.7/unittest/lsp5.txt | 18 + codec2/branches/0.7/unittest/lsp6.txt | 18 + codec2/branches/0.7/unittest/lsp7.txt | 18 + codec2/branches/0.7/unittest/lsp8.txt | 10 + codec2/branches/0.7/unittest/lsp9.txt | 10 + codec2/branches/0.7/unittest/lspd456.txt | 1024 + codec2/branches/0.7/unittest/lspd678910.txt | 1025 + codec2/branches/0.7/unittest/lspd78.txt | 64 + codec2/branches/0.7/unittest/lspd910.txt | 64 + codec2/branches/0.7/unittest/lspjnd5-10.txt | 8317 +++ codec2/branches/0.7/unittest/mksine.c | 42 + codec2/branches/0.7/unittest/polar2rect.c | 54 + codec2/branches/0.7/unittest/pre.c | 59 + codec2/branches/0.7/unittest/raw2h.c | 45 + codec2/branches/0.7/unittest/run_tests.sh | 27 + codec2/branches/0.7/unittest/scalarlsptest.c | 110 + codec2/branches/0.7/unittest/sd.c | 83 + codec2/branches/0.7/unittest/sd.h | 33 + codec2/branches/0.7/unittest/speexlsptest.c | 176 + codec2/branches/0.7/unittest/speexnoisesup.c | 59 + codec2/branches/0.7/unittest/t16_8.c | 111 + codec2/branches/0.7/unittest/t16_8_short.c | 95 + codec2/branches/0.7/unittest/t48_8.c | 112 + codec2/branches/0.7/unittest/tcodec2.c | 220 + codec2/branches/0.7/unittest/tcohpsk.c | 286 + codec2/branches/0.7/unittest/tcontphase.c | 186 + codec2/branches/0.7/unittest/tdec.c | 133 + codec2/branches/0.7/unittest/tdeframer.c | 148 + codec2/branches/0.7/unittest/test_cohpsk_ch.c | 296 + codec2/branches/0.7/unittest/tfdmdv.c | 287 + codec2/branches/0.7/unittest/tfifo.c | 103 + codec2/branches/0.7/unittest/tfmfsk.c | 198 + .../0.7/unittest/tfreedv_data_channel.c | 292 + codec2/branches/0.7/unittest/tfsk.c | 232 + codec2/branches/0.7/unittest/tinterp.c | 151 + codec2/branches/0.7/unittest/tlininterp.c | 153 + codec2/branches/0.7/unittest/tlspsens.c | 131 + codec2/branches/0.7/unittest/tnewamp1.c | 288 + codec2/branches/0.7/unittest/tnlp.c | 164 + codec2/branches/0.7/unittest/tofdm.c | 306 + codec2/branches/0.7/unittest/tprede.c | 53 + codec2/branches/0.7/unittest/tquant.c | 214 + codec2/branches/0.7/unittest/tsrc.c | 109 + codec2/branches/0.7/unittest/vq_train_jvm.c | 487 + codec2/branches/0.7/unittest/vqtrain.c | 304 + codec2/branches/0.7/wav/all.wav | Bin 0 -> 913868 bytes codec2/branches/0.7/wav/cross.wav | Bin 0 -> 24058 bytes codec2/branches/0.7/wav/cross_melp2400.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/f2400.wav | Bin 0 -> 27726 bytes codec2/branches/0.7/wav/forig.wav | Bin 0 -> 25268 bytes codec2/branches/0.7/wav/forig_ambe2000.wav | Bin 0 -> 32044 bytes codec2/branches/0.7/wav/forig_speex_8k.wav | Bin 0 -> 25324 bytes codec2/branches/0.7/wav/hts1a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts1a_ambe2000.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts1a_c2_v0.1.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts1a_c2_v0.1a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts1a_g729a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts1a_lpc10.wav | Bin 0 -> 46844 bytes codec2/branches/0.7/wav/hts1a_speex_8k.wav | Bin 0 -> 48000 bytes codec2/branches/0.7/wav/hts2a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts2a_ambe2000.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts2a_c2_v0.1.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts2a_c2_v0.1a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts2a_g729a.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/hts2a_lpc10.wav | Bin 0 -> 46844 bytes codec2/branches/0.7/wav/hts2a_speex_8k.wav | Bin 0 -> 47824 bytes codec2/branches/0.7/wav/m2400.wav | Bin 0 -> 33668 bytes codec2/branches/0.7/wav/mmt1.wav | Bin 0 -> 64044 bytes codec2/branches/0.7/wav/mmt1_ambe2000.wav | Bin 0 -> 64044 bytes codec2/branches/0.7/wav/mmt1_c2_v01a.wav | Bin 0 -> 64044 bytes codec2/branches/0.7/wav/mmt1_lpc10.wav | Bin 0 -> 63044 bytes codec2/branches/0.7/wav/mmt1_speex_8k.wav | Bin 0 -> 64044 bytes codec2/branches/0.7/wav/morig.wav | Bin 0 -> 32100 bytes codec2/branches/0.7/wav/morig_ambe2000.wav | Bin 0 -> 48044 bytes codec2/branches/0.7/wav/morig_speex_8k.wav | Bin 0 -> 32100 bytes codec2/branches/0.7/wav/ve9qrp.wav | Bin 0 -> 1799212 bytes codec2/branches/0.7/wav/vk5qi.wav | Bin 0 -> 216760 bytes codec2/branches/0.7/wav/x200_ext.wav | Bin 0 -> 160044 bytes codec2/branches/0.7/wav/x200_int.wav | Bin 0 -> 160044 bytes freedv/branches/1.2/CMakeLists.txt | 26 +- freedv/branches/1.2/README.txt | 276 +- freedv/branches/1.2/RELEASE_NOTES.txt | 7 + freedv/branches/1.2/USER_MANUAL.txt | 100 + .../branches/1.2/freedv-dev/.clang/.gitignore | 0 freedv/branches/1.2/freedv-dev/CMakeLists.txt | 463 + freedv/branches/1.2/freedv-dev/COPYING | 502 + freedv/branches/1.2/freedv-dev/README.osx | 107 + freedv/branches/1.2/freedv-dev/README.txt | 233 + .../branches/1.2/freedv-dev/RELEASE_NOTES.txt | 7 + .../branches/1.2/freedv-dev/USER_MANUAL.txt | 100 + .../1.2/freedv-dev/cmake/BuildCodec2.cmake | 26 + .../1.2/freedv-dev/cmake/BuildHamlib.cmake | 20 + .../1.2/freedv-dev/cmake/BuildPortaudio.cmake | 52 + .../freedv-dev/cmake/BuildSamplerate.cmake | 27 + .../1.2/freedv-dev/cmake/BuildSndfile.cmake | 26 + .../1.2/freedv-dev/cmake/BuildSpeex.cmake | 30 + .../1.2/freedv-dev/cmake/BuildWxWidgets.cmake | 43 + .../1.2/freedv-dev/cmake/FindPortaudio.cmake | 107 + .../freedv-dev/cmake/GetDependencies.cmake.in | 37 + .../branches/1.2/freedv-dev/cmake/MinGW.cmake | 8 + .../cmake/Toolchain-Ubuntu-mingw32.cmake | 25 + .../branches/1.2/freedv-dev/cmake/config.h.in | 19 + .../1.2/freedv-dev/cmake/soxconfig.h.in | 16 + .../1.2/freedv-dev/cmake/version.h.in | 11 + .../1.2/freedv-dev/contrib/CMakeLists.txt | 22 + .../branches/1.2/freedv-dev/contrib/LICENSE | 393 + .../1.2/freedv-dev/contrib/freedv.desktop | 8 + .../1.2/freedv-dev/contrib/freedv.ico | Bin 0 -> 364646 bytes .../branches/1.2/freedv-dev/contrib/freedv.rc | 1 + .../1.2/freedv-dev/contrib/freedv128x128.png | Bin 0 -> 22063 bytes .../1.2/freedv-dev/contrib/freedv256x256.png | Bin 0 -> 72148 bytes .../1.2/freedv-dev/contrib/freedv48x48.png | Bin 0 -> 3787 bytes .../1.2/freedv-dev/contrib/freedv64x64.png | Bin 0 -> 6289 bytes .../freedv-dev/contrib/freedv_screenshot.png | Bin 0 -> 81690 bytes freedv/branches/1.2/freedv-dev/credits.txt | 13 + freedv/branches/1.2/freedv-dev/db/current | 1 + freedv/branches/1.2/freedv-dev/db/format | 2 + freedv/branches/1.2/freedv-dev/db/fs-type | 1 + freedv/branches/1.2/freedv-dev/db/fsfs.conf | 38 + .../1.2/freedv-dev/db/min-unpacked-rev | 1 + .../branches/1.2/freedv-dev/db/rep-cache.db | Bin 0 -> 4096 bytes .../branches/1.2/freedv-dev/db/revprops/0/0 | 5 + .../branches/1.2/freedv-dev/db/revprops/0/1 | 13 + freedv/branches/1.2/freedv-dev/db/revs/0/0 | 11 + freedv/branches/1.2/freedv-dev/db/revs/0/1 | 49 + .../1.2/freedv-dev/db/transactions/.gitignore | 0 freedv/branches/1.2/freedv-dev/db/txn-current | 1 + .../1.2/freedv-dev/db/txn-current-lock | 0 .../freedv-dev/db/txn-protorevs/.gitignore | 0 freedv/branches/1.2/freedv-dev/db/uuid | 1 + freedv/branches/1.2/freedv-dev/db/write-lock | 0 .../branches/1.2/freedv-dev/debian/changelog | 5 + freedv/branches/1.2/freedv-dev/debian/compat | 1 + freedv/branches/1.2/freedv-dev/debian/control | 19 + .../branches/1.2/freedv-dev/debian/copyright | 38 + freedv/branches/1.2/freedv-dev/debian/docs | 3 + freedv/branches/1.2/freedv-dev/debian/format | 1 + freedv/branches/1.2/freedv-dev/debian/rules | 30 + freedv/branches/1.2/freedv-dev/script/spot.sh | 29 + .../1.2/freedv-dev/src/CMakeLists.txt | 79 + .../1.2/freedv-dev/src/Makefile.win32 | 52 + .../1.2/freedv-dev/src/afreedvplugin.c | 117 + freedv/branches/1.2/freedv-dev/src/comp.h | 39 + .../1.2/freedv-dev/src/dlg_audiooptions.cpp | 1264 + .../1.2/freedv-dev/src/dlg_audiooptions.h | 176 + .../1.2/freedv-dev/src/dlg_filter.cpp | 785 + .../branches/1.2/freedv-dev/src/dlg_filter.h | 166 + .../1.2/freedv-dev/src/dlg_options.cpp | 616 + .../branches/1.2/freedv-dev/src/dlg_options.h | 137 + .../1.2/freedv-dev/src/dlg_plugin.cpp | 148 + .../branches/1.2/freedv-dev/src/dlg_plugin.h | 65 + .../branches/1.2/freedv-dev/src/dlg_ptt.cpp | 570 + freedv/branches/1.2/freedv-dev/src/dlg_ptt.h | 95 + .../1.2/freedv-dev/src/fdmdv2_defines.h | 106 + .../1.2/freedv-dev/src/fdmdv2_main.cpp | 4042 ++ .../branches/1.2/freedv-dev/src/fdmdv2_main.h | 681 + .../1.2/freedv-dev/src/fdmdv2_pa_wrapper.cpp | 324 + .../1.2/freedv-dev/src/fdmdv2_pa_wrapper.h | 115 + .../1.2/freedv-dev/src/fdmdv2_plot.cpp | 283 + .../branches/1.2/freedv-dev/src/fdmdv2_plot.h | 150 + .../1.2/freedv-dev/src/fdmdv2_plot_scalar.cpp | 344 + .../1.2/freedv-dev/src/fdmdv2_plot_scalar.h | 78 + .../freedv-dev/src/fdmdv2_plot_scatter.cpp | 289 + .../1.2/freedv-dev/src/fdmdv2_plot_scatter.h | 65 + .../freedv-dev/src/fdmdv2_plot_spectrum.cpp | 267 + .../1.2/freedv-dev/src/fdmdv2_plot_spectrum.h | 58 + .../freedv-dev/src/fdmdv2_plot_waterfall.cpp | 483 + .../freedv-dev/src/fdmdv2_plot_waterfall.h | 73 + .../branches/1.2/freedv-dev/src/freedv.icns | Bin 0 -> 92136 bytes freedv/branches/1.2/freedv-dev/src/hamlib.cpp | 160 + freedv/branches/1.2/freedv-dev/src/hamlib.h | 31 + freedv/branches/1.2/freedv-dev/src/info.plist | 104 + .../1.2/freedv-dev/src/serialport.cpp | 234 + .../branches/1.2/freedv-dev/src/serialport.h | 42 + freedv/branches/1.2/freedv-dev/src/sox/band.h | 47 + .../branches/1.2/freedv-dev/src/sox/biquad.c | 178 + .../branches/1.2/freedv-dev/src/sox/biquad.h | 78 + .../branches/1.2/freedv-dev/src/sox/biquads.c | 400 + .../branches/1.2/freedv-dev/src/sox/effects.c | 544 + .../branches/1.2/freedv-dev/src/sox/effects.h | 22 + .../1.2/freedv-dev/src/sox/effects_i.c | 379 + .../1.2/freedv-dev/src/sox/formats_i.c | 487 + .../branches/1.2/freedv-dev/src/sox/libsox.c | 225 + freedv/branches/1.2/freedv-dev/src/sox/sox.h | 2608 + .../branches/1.2/freedv-dev/src/sox/sox_i.h | 417 + .../branches/1.2/freedv-dev/src/sox/soxomp.h | 38 + freedv/branches/1.2/freedv-dev/src/sox/util.h | 231 + .../branches/1.2/freedv-dev/src/sox/xmalloc.c | 43 + .../branches/1.2/freedv-dev/src/sox/xmalloc.h | 34 + .../branches/1.2/freedv-dev/src/sox_biquad.c | 134 + .../branches/1.2/freedv-dev/src/sox_biquad.h | 40 + .../branches/1.2/freedv-dev/src/topFrame.cpp | 595 + freedv/branches/1.2/freedv-dev/src/topFrame.h | 194 + freedv/branches/1.2/src/CMakeLists.txt | 1 + freedv/branches/1.2/src/dlg_options.cpp | 311 +- freedv/branches/1.2/src/dlg_options.h | 40 +- freedv/branches/1.2/src/dlg_ptt.cpp | 268 +- freedv/branches/1.2/src/dlg_ptt.h | 15 +- freedv/branches/1.2/src/fdmdv2_main.cpp | 362 +- freedv/branches/1.2/src/fdmdv2_main.h | 51 +- freedv/branches/1.2/src/hamlib.cpp | 65 +- freedv/branches/1.2/src/hamlib.h | 5 +- freedv/branches/1.2/src/serialport.cpp | 234 + freedv/branches/1.2/src/serialport.h | 42 + freedv/branches/1.2/src/topFrame.cpp | 4 +- freedv/tags/1.2.2/.clang/.gitignore | 0 freedv/tags/1.2.2/CMakeLists.txt | 463 + freedv/tags/1.2.2/COPYING | 502 + freedv/tags/1.2.2/README.osx | 107 + freedv/tags/1.2.2/README.txt | 233 + freedv/tags/1.2.2/RELEASE_NOTES.txt | 7 + freedv/tags/1.2.2/USER_MANUAL.txt | 100 + freedv/tags/1.2.2/cmake/BuildCodec2.cmake | 25 + freedv/tags/1.2.2/cmake/BuildHamlib.cmake | 20 + freedv/tags/1.2.2/cmake/BuildPortaudio.cmake | 52 + freedv/tags/1.2.2/cmake/BuildSamplerate.cmake | 27 + freedv/tags/1.2.2/cmake/BuildSndfile.cmake | 26 + freedv/tags/1.2.2/cmake/BuildSpeex.cmake | 26 + freedv/tags/1.2.2/cmake/BuildWxWidgets.cmake | 43 + freedv/tags/1.2.2/cmake/FindPortaudio.cmake | 107 + .../tags/1.2.2/cmake/GetDependencies.cmake.in | 37 + freedv/tags/1.2.2/cmake/MinGW.cmake | 8 + .../cmake/Toolchain-Ubuntu-mingw32.cmake | 25 + freedv/tags/1.2.2/cmake/config.h.in | 19 + freedv/tags/1.2.2/cmake/soxconfig.h.in | 16 + freedv/tags/1.2.2/cmake/version.h.in | 11 + freedv/tags/1.2.2/contrib/CMakeLists.txt | 22 + freedv/tags/1.2.2/contrib/LICENSE | 393 + freedv/tags/1.2.2/contrib/freedv.desktop | 8 + freedv/tags/1.2.2/contrib/freedv.ico | Bin 0 -> 364646 bytes freedv/tags/1.2.2/contrib/freedv.rc | 1 + freedv/tags/1.2.2/contrib/freedv128x128.png | Bin 0 -> 22063 bytes freedv/tags/1.2.2/contrib/freedv256x256.png | Bin 0 -> 72148 bytes freedv/tags/1.2.2/contrib/freedv48x48.png | Bin 0 -> 3787 bytes freedv/tags/1.2.2/contrib/freedv64x64.png | Bin 0 -> 6289 bytes .../tags/1.2.2/contrib/freedv_screenshot.png | Bin 0 -> 81690 bytes freedv/tags/1.2.2/credits.txt | 13 + freedv/tags/1.2.2/db/current | 1 + freedv/tags/1.2.2/db/format | 2 + freedv/tags/1.2.2/db/fs-type | 1 + freedv/tags/1.2.2/db/fsfs.conf | 38 + freedv/tags/1.2.2/db/min-unpacked-rev | 1 + freedv/tags/1.2.2/db/rep-cache.db | Bin 0 -> 4096 bytes freedv/tags/1.2.2/db/revprops/0/0 | 5 + freedv/tags/1.2.2/db/revprops/0/1 | 13 + freedv/tags/1.2.2/db/revs/0/0 | 11 + freedv/tags/1.2.2/db/revs/0/1 | 49 + freedv/tags/1.2.2/db/transactions/.gitignore | 0 freedv/tags/1.2.2/db/txn-current | 1 + freedv/tags/1.2.2/db/txn-current-lock | 0 freedv/tags/1.2.2/db/txn-protorevs/.gitignore | 0 freedv/tags/1.2.2/db/uuid | 1 + freedv/tags/1.2.2/db/write-lock | 0 freedv/tags/1.2.2/debian/changelog | 5 + freedv/tags/1.2.2/debian/compat | 1 + freedv/tags/1.2.2/debian/control | 19 + freedv/tags/1.2.2/debian/copyright | 38 + freedv/tags/1.2.2/debian/docs | 3 + freedv/tags/1.2.2/debian/format | 1 + freedv/tags/1.2.2/debian/rules | 30 + .../tags/1.2.2/freedv-dev/.clang/.gitignore | 0 freedv/tags/1.2.2/freedv-dev/CMakeLists.txt | 463 + freedv/tags/1.2.2/freedv-dev/COPYING | 502 + freedv/tags/1.2.2/freedv-dev/README.osx | 107 + freedv/tags/1.2.2/freedv-dev/README.txt | 233 + .../tags/1.2.2/freedv-dev/RELEASE_NOTES.txt | 7 + freedv/tags/1.2.2/freedv-dev/USER_MANUAL.txt | 100 + .../1.2.2/freedv-dev/cmake/BuildCodec2.cmake | 26 + .../1.2.2/freedv-dev/cmake/BuildHamlib.cmake | 20 + .../freedv-dev/cmake/BuildPortaudio.cmake | 52 + .../freedv-dev/cmake/BuildSamplerate.cmake | 27 + .../1.2.2/freedv-dev/cmake/BuildSndfile.cmake | 26 + .../1.2.2/freedv-dev/cmake/BuildSpeex.cmake | 30 + .../freedv-dev/cmake/BuildWxWidgets.cmake | 43 + .../freedv-dev/cmake/FindPortaudio.cmake | 107 + .../freedv-dev/cmake/GetDependencies.cmake.in | 37 + .../tags/1.2.2/freedv-dev/cmake/MinGW.cmake | 8 + .../cmake/Toolchain-Ubuntu-mingw32.cmake | 25 + .../tags/1.2.2/freedv-dev/cmake/config.h.in | 19 + .../1.2.2/freedv-dev/cmake/soxconfig.h.in | 16 + .../tags/1.2.2/freedv-dev/cmake/version.h.in | 11 + .../1.2.2/freedv-dev/contrib/CMakeLists.txt | 22 + freedv/tags/1.2.2/freedv-dev/contrib/LICENSE | 393 + .../1.2.2/freedv-dev/contrib/freedv.desktop | 8 + .../tags/1.2.2/freedv-dev/contrib/freedv.ico | Bin 0 -> 364646 bytes .../tags/1.2.2/freedv-dev/contrib/freedv.rc | 1 + .../freedv-dev/contrib/freedv128x128.png | Bin 0 -> 22063 bytes .../freedv-dev/contrib/freedv256x256.png | Bin 0 -> 72148 bytes .../1.2.2/freedv-dev/contrib/freedv48x48.png | Bin 0 -> 3787 bytes .../1.2.2/freedv-dev/contrib/freedv64x64.png | Bin 0 -> 6289 bytes .../freedv-dev/contrib/freedv_screenshot.png | Bin 0 -> 81690 bytes freedv/tags/1.2.2/freedv-dev/credits.txt | 13 + freedv/tags/1.2.2/freedv-dev/db/current | 1 + freedv/tags/1.2.2/freedv-dev/db/format | 2 + freedv/tags/1.2.2/freedv-dev/db/fs-type | 1 + freedv/tags/1.2.2/freedv-dev/db/fsfs.conf | 38 + .../tags/1.2.2/freedv-dev/db/min-unpacked-rev | 1 + freedv/tags/1.2.2/freedv-dev/db/rep-cache.db | Bin 0 -> 4096 bytes freedv/tags/1.2.2/freedv-dev/db/revprops/0/0 | 5 + freedv/tags/1.2.2/freedv-dev/db/revprops/0/1 | 13 + freedv/tags/1.2.2/freedv-dev/db/revs/0/0 | 11 + freedv/tags/1.2.2/freedv-dev/db/revs/0/1 | 49 + .../freedv-dev/db/transactions/.gitignore | 0 freedv/tags/1.2.2/freedv-dev/db/txn-current | 1 + .../tags/1.2.2/freedv-dev/db/txn-current-lock | 0 .../freedv-dev/db/txn-protorevs/.gitignore | 0 freedv/tags/1.2.2/freedv-dev/db/uuid | 1 + freedv/tags/1.2.2/freedv-dev/db/write-lock | 0 freedv/tags/1.2.2/freedv-dev/debian/changelog | 5 + freedv/tags/1.2.2/freedv-dev/debian/compat | 1 + freedv/tags/1.2.2/freedv-dev/debian/control | 19 + freedv/tags/1.2.2/freedv-dev/debian/copyright | 38 + freedv/tags/1.2.2/freedv-dev/debian/docs | 3 + freedv/tags/1.2.2/freedv-dev/debian/format | 1 + freedv/tags/1.2.2/freedv-dev/debian/rules | 30 + freedv/tags/1.2.2/freedv-dev/script/spot.sh | 29 + .../tags/1.2.2/freedv-dev/src/CMakeLists.txt | 79 + .../tags/1.2.2/freedv-dev/src/Makefile.win32 | 52 + .../tags/1.2.2/freedv-dev/src/afreedvplugin.c | 117 + freedv/tags/1.2.2/freedv-dev/src/comp.h | 39 + .../1.2.2/freedv-dev/src/dlg_audiooptions.cpp | 1264 + .../1.2.2/freedv-dev/src/dlg_audiooptions.h | 176 + .../tags/1.2.2/freedv-dev/src/dlg_filter.cpp | 785 + freedv/tags/1.2.2/freedv-dev/src/dlg_filter.h | 166 + .../tags/1.2.2/freedv-dev/src/dlg_options.cpp | 616 + .../tags/1.2.2/freedv-dev/src/dlg_options.h | 137 + .../tags/1.2.2/freedv-dev/src/dlg_plugin.cpp | 148 + freedv/tags/1.2.2/freedv-dev/src/dlg_plugin.h | 65 + freedv/tags/1.2.2/freedv-dev/src/dlg_ptt.cpp | 570 + freedv/tags/1.2.2/freedv-dev/src/dlg_ptt.h | 95 + .../1.2.2/freedv-dev/src/fdmdv2_defines.h | 106 + .../tags/1.2.2/freedv-dev/src/fdmdv2_main.cpp | 4042 ++ .../tags/1.2.2/freedv-dev/src/fdmdv2_main.h | 681 + .../freedv-dev/src/fdmdv2_pa_wrapper.cpp | 324 + .../1.2.2/freedv-dev/src/fdmdv2_pa_wrapper.h | 115 + .../tags/1.2.2/freedv-dev/src/fdmdv2_plot.cpp | 283 + .../tags/1.2.2/freedv-dev/src/fdmdv2_plot.h | 150 + .../freedv-dev/src/fdmdv2_plot_scalar.cpp | 344 + .../1.2.2/freedv-dev/src/fdmdv2_plot_scalar.h | 78 + .../freedv-dev/src/fdmdv2_plot_scatter.cpp | 289 + .../freedv-dev/src/fdmdv2_plot_scatter.h | 65 + .../freedv-dev/src/fdmdv2_plot_spectrum.cpp | 267 + .../freedv-dev/src/fdmdv2_plot_spectrum.h | 58 + .../freedv-dev/src/fdmdv2_plot_waterfall.cpp | 483 + .../freedv-dev/src/fdmdv2_plot_waterfall.h | 73 + freedv/tags/1.2.2/freedv-dev/src/freedv.icns | Bin 0 -> 92136 bytes freedv/tags/1.2.2/freedv-dev/src/hamlib.cpp | 160 + freedv/tags/1.2.2/freedv-dev/src/hamlib.h | 31 + freedv/tags/1.2.2/freedv-dev/src/info.plist | 104 + .../tags/1.2.2/freedv-dev/src/serialport.cpp | 234 + freedv/tags/1.2.2/freedv-dev/src/serialport.h | 42 + freedv/tags/1.2.2/freedv-dev/src/sox/band.h | 47 + freedv/tags/1.2.2/freedv-dev/src/sox/biquad.c | 178 + freedv/tags/1.2.2/freedv-dev/src/sox/biquad.h | 78 + .../tags/1.2.2/freedv-dev/src/sox/biquads.c | 400 + .../tags/1.2.2/freedv-dev/src/sox/effects.c | 544 + .../tags/1.2.2/freedv-dev/src/sox/effects.h | 22 + .../tags/1.2.2/freedv-dev/src/sox/effects_i.c | 379 + .../tags/1.2.2/freedv-dev/src/sox/formats_i.c | 487 + freedv/tags/1.2.2/freedv-dev/src/sox/libsox.c | 225 + freedv/tags/1.2.2/freedv-dev/src/sox/sox.h | 2608 + freedv/tags/1.2.2/freedv-dev/src/sox/sox_i.h | 417 + freedv/tags/1.2.2/freedv-dev/src/sox/soxomp.h | 38 + freedv/tags/1.2.2/freedv-dev/src/sox/util.h | 231 + .../tags/1.2.2/freedv-dev/src/sox/xmalloc.c | 43 + .../tags/1.2.2/freedv-dev/src/sox/xmalloc.h | 34 + freedv/tags/1.2.2/freedv-dev/src/sox_biquad.c | 134 + freedv/tags/1.2.2/freedv-dev/src/sox_biquad.h | 40 + freedv/tags/1.2.2/freedv-dev/src/topFrame.cpp | 595 + freedv/tags/1.2.2/freedv-dev/src/topFrame.h | 194 + freedv/tags/1.2.2/script/spot.sh | 29 + freedv/tags/1.2.2/src/CMakeLists.txt | 79 + freedv/tags/1.2.2/src/Makefile.win32 | 52 + freedv/tags/1.2.2/src/afreedvplugin.c | 117 + freedv/tags/1.2.2/src/comp.h | 39 + freedv/tags/1.2.2/src/dlg_audiooptions.cpp | 1264 + freedv/tags/1.2.2/src/dlg_audiooptions.h | 176 + freedv/tags/1.2.2/src/dlg_filter.cpp | 785 + freedv/tags/1.2.2/src/dlg_filter.h | 166 + freedv/tags/1.2.2/src/dlg_options.cpp | 616 + freedv/tags/1.2.2/src/dlg_options.h | 137 + freedv/tags/1.2.2/src/dlg_plugin.cpp | 148 + freedv/tags/1.2.2/src/dlg_plugin.h | 65 + freedv/tags/1.2.2/src/dlg_ptt.cpp | 570 + freedv/tags/1.2.2/src/dlg_ptt.h | 93 + freedv/tags/1.2.2/src/fdmdv2_defines.h | 106 + freedv/tags/1.2.2/src/fdmdv2_main.cpp | 3943 + freedv/tags/1.2.2/src/fdmdv2_main.h | 681 + freedv/tags/1.2.2/src/fdmdv2_pa_wrapper.cpp | 324 + freedv/tags/1.2.2/src/fdmdv2_pa_wrapper.h | 115 + freedv/tags/1.2.2/src/fdmdv2_plot.cpp | 283 + freedv/tags/1.2.2/src/fdmdv2_plot.h | 150 + freedv/tags/1.2.2/src/fdmdv2_plot_scalar.cpp | 281 + freedv/tags/1.2.2/src/fdmdv2_plot_scalar.h | 73 + freedv/tags/1.2.2/src/fdmdv2_plot_scatter.cpp | 289 + freedv/tags/1.2.2/src/fdmdv2_plot_scatter.h | 65 + .../tags/1.2.2/src/fdmdv2_plot_spectrum.cpp | 267 + freedv/tags/1.2.2/src/fdmdv2_plot_spectrum.h | 58 + .../tags/1.2.2/src/fdmdv2_plot_waterfall.cpp | 483 + freedv/tags/1.2.2/src/fdmdv2_plot_waterfall.h | 73 + freedv/tags/1.2.2/src/freedv.icns | Bin 0 -> 92136 bytes freedv/tags/1.2.2/src/hamlib.cpp | 160 + freedv/tags/1.2.2/src/hamlib.h | 31 + freedv/tags/1.2.2/src/info.plist | 104 + freedv/tags/1.2.2/src/serialport.cpp | 234 + freedv/tags/1.2.2/src/serialport.h | 42 + freedv/tags/1.2.2/src/sox/band.h | 47 + freedv/tags/1.2.2/src/sox/biquad.c | 178 + freedv/tags/1.2.2/src/sox/biquad.h | 78 + freedv/tags/1.2.2/src/sox/biquads.c | 400 + freedv/tags/1.2.2/src/sox/effects.c | 544 + freedv/tags/1.2.2/src/sox/effects.h | 22 + freedv/tags/1.2.2/src/sox/effects_i.c | 379 + freedv/tags/1.2.2/src/sox/formats_i.c | 487 + freedv/tags/1.2.2/src/sox/libsox.c | 225 + freedv/tags/1.2.2/src/sox/sox.h | 2608 + freedv/tags/1.2.2/src/sox/sox_i.h | 417 + freedv/tags/1.2.2/src/sox/soxomp.h | 38 + freedv/tags/1.2.2/src/sox/util.h | 231 + freedv/tags/1.2.2/src/sox/xmalloc.c | 43 + freedv/tags/1.2.2/src/sox/xmalloc.h | 34 + freedv/tags/1.2.2/src/sox_biquad.c | 134 + freedv/tags/1.2.2/src/sox_biquad.h | 40 + freedv/tags/1.2.2/src/topFrame.cpp | 592 + freedv/tags/1.2.2/src/topFrame.h | 193 + 1033 files changed, 317622 insertions(+), 650 deletions(-) create mode 100644 codec2/branches/0.7/CMakeLists.txt create mode 100644 codec2/branches/0.7/COPYING create mode 100644 codec2/branches/0.7/INSTALL create mode 100644 codec2/branches/0.7/README create mode 100644 codec2/branches/0.7/README_fdmdv.txt create mode 100644 codec2/branches/0.7/README_fsk.txt create mode 100644 codec2/branches/0.7/cmake/GetDependencies.cmake.in create mode 100644 codec2/branches/0.7/cmake/config.h.in create mode 100644 codec2/branches/0.7/codec2.pc.in create mode 100644 codec2/branches/0.7/debian/changelog create mode 100644 codec2/branches/0.7/debian/codec2.doc-base.EX create mode 100644 codec2/branches/0.7/debian/codec2.install create mode 100644 codec2/branches/0.7/debian/codec21.dirs create mode 100644 codec2/branches/0.7/debian/codec21.install create mode 100644 codec2/branches/0.7/debian/compat create mode 100644 codec2/branches/0.7/debian/control create mode 100644 codec2/branches/0.7/debian/copyright create mode 100644 codec2/branches/0.7/debian/docs create mode 100644 codec2/branches/0.7/debian/libcodec2-dev.dirs create mode 100644 codec2/branches/0.7/debian/libcodec2-dev.install create mode 100644 codec2/branches/0.7/debian/libcodec2.install create mode 100755 codec2/branches/0.7/debian/rules create mode 100644 codec2/branches/0.7/debian/source/format create mode 100644 codec2/branches/0.7/octave/2400ab_frame_design.ods create mode 100644 codec2/branches/0.7/octave/H2064_516_sparse.mat create mode 100644 codec2/branches/0.7/octave/HRA_112_112.txt create mode 100644 codec2/branches/0.7/octave/HRA_112_56.txt create mode 100644 codec2/branches/0.7/octave/HRA_56_28.txt create mode 100644 codec2/branches/0.7/octave/HRA_56_56.txt create mode 100644 codec2/branches/0.7/octave/Mat2Hrows.m create mode 100755 codec2/branches/0.7/octave/adc_plot_spec.m create mode 100644 codec2/branches/0.7/octave/adc_sfdr_ut.m create mode 100644 codec2/branches/0.7/octave/adcres.m create mode 100644 codec2/branches/0.7/octave/autotest.m create mode 100644 codec2/branches/0.7/octave/av_imp.m create mode 100644 codec2/branches/0.7/octave/bandpasssampling.m create mode 100644 codec2/branches/0.7/octave/bfq19ssa.m create mode 100644 codec2/branches/0.7/octave/bpf.m create mode 100644 codec2/branches/0.7/octave/bpsk.m create mode 100644 codec2/branches/0.7/octave/c2wideband_batch.m create mode 100644 codec2/branches/0.7/octave/c2wideband_const.m create mode 100644 codec2/branches/0.7/octave/c2wideband_fbf.m create mode 100644 codec2/branches/0.7/octave/cbphase.m create mode 100644 codec2/branches/0.7/octave/cellmodem.m create mode 100644 codec2/branches/0.7/octave/ciccomp.m create mode 100644 codec2/branches/0.7/octave/cma.m create mode 100644 codec2/branches/0.7/octave/cml.patch create mode 100644 codec2/branches/0.7/octave/codec2_demo.m create mode 100644 codec2/branches/0.7/octave/cohpsk.m create mode 100644 codec2/branches/0.7/octave/cohpsk_demod_plot.m create mode 100644 codec2/branches/0.7/octave/cohpsk_frame_design.ods create mode 100644 codec2/branches/0.7/octave/cohpsk_plots.m create mode 100644 codec2/branches/0.7/octave/crc16.m create mode 100644 codec2/branches/0.7/octave/cspec.m create mode 100644 codec2/branches/0.7/octave/dacres.m create mode 100644 codec2/branches/0.7/octave/df_mixer.m create mode 100644 codec2/branches/0.7/octave/diff_codec.m create mode 100644 codec2/branches/0.7/octave/doppler_spread.m create mode 100644 codec2/branches/0.7/octave/doppler_spread_ut.m create mode 100644 codec2/branches/0.7/octave/estsnr.m create mode 100644 codec2/branches/0.7/octave/fdmdv.m create mode 100644 codec2/branches/0.7/octave/fdmdv_demod.m create mode 100644 codec2/branches/0.7/octave/fdmdv_demod_c.m create mode 100644 codec2/branches/0.7/octave/fdmdv_demod_coh.m create mode 100644 codec2/branches/0.7/octave/fdmdv_mod.m create mode 100644 codec2/branches/0.7/octave/fdmdv_sweep.m create mode 100644 codec2/branches/0.7/octave/fdmdv_ut.m create mode 100644 codec2/branches/0.7/octave/fdmdv_ut_coh.m create mode 100644 codec2/branches/0.7/octave/fdmdv_ut_freq_off.m create mode 100644 codec2/branches/0.7/octave/fm.m create mode 100644 codec2/branches/0.7/octave/fm_radio_filt_model.txt create mode 100644 codec2/branches/0.7/octave/fmfsk.m create mode 100644 codec2/branches/0.7/octave/fsk.m create mode 100644 codec2/branches/0.7/octave/fsk4.m create mode 100644 codec2/branches/0.7/octave/fsk_basic.m create mode 100644 codec2/branches/0.7/octave/fsk_cont_phase.m create mode 100644 codec2/branches/0.7/octave/fsk_eme.m create mode 100644 codec2/branches/0.7/octave/fsk_horus.m create mode 100644 codec2/branches/0.7/octave/fsk_horus_2fsk.m create mode 100755 codec2/branches/0.7/octave/fsk_horus_stream.m create mode 100644 codec2/branches/0.7/octave/fsk_lib.m create mode 100644 codec2/branches/0.7/octave/fskdemodgui.py create mode 100644 codec2/branches/0.7/octave/fuzzy_gray.m create mode 100644 codec2/branches/0.7/octave/gen_complex_short.m create mode 100644 codec2/branches/0.7/octave/gen_rn_coeffs.m create mode 100644 codec2/branches/0.7/octave/glottal.m create mode 100644 codec2/branches/0.7/octave/gmsk.m create mode 100644 codec2/branches/0.7/octave/gp_interleaver.m create mode 100644 codec2/branches/0.7/octave/hackrf_dc.m create mode 100644 codec2/branches/0.7/octave/hackrf_twotone.m create mode 100644 codec2/branches/0.7/octave/hackrf_uc.m create mode 100644 codec2/branches/0.7/octave/hf_modem_curves.m create mode 100644 codec2/branches/0.7/octave/hf_sim.m create mode 100644 codec2/branches/0.7/octave/hfper.m create mode 100644 codec2/branches/0.7/octave/horus_high_speed.bin create mode 100644 codec2/branches/0.7/octave/horus_msg.txt create mode 100644 codec2/branches/0.7/octave/horus_payload_rtty.txt create mode 100644 codec2/branches/0.7/octave/horus_tx_bits_binary.txt create mode 100644 codec2/branches/0.7/octave/hp_filt.m create mode 100644 codec2/branches/0.7/octave/impulse_noise.m create mode 100644 codec2/branches/0.7/octave/kmeans2.m create mode 100644 codec2/branches/0.7/octave/kmeans_tests.m create mode 100644 codec2/branches/0.7/octave/ldpc.m create mode 100644 codec2/branches/0.7/octave/ldpc_fsk_lib.m create mode 100644 codec2/branches/0.7/octave/ldpc_gen_h_file.m create mode 100644 codec2/branches/0.7/octave/ldpc_qpsk.m create mode 100644 codec2/branches/0.7/octave/ldpc_short.m create mode 100644 codec2/branches/0.7/octave/ldpcdec.m create mode 100644 codec2/branches/0.7/octave/ldpcenc.m create mode 100644 codec2/branches/0.7/octave/ldpcut.m create mode 100644 codec2/branches/0.7/octave/linreg.m create mode 100644 codec2/branches/0.7/octave/load_comp.m create mode 100644 codec2/branches/0.7/octave/load_hackrf.m create mode 100644 codec2/branches/0.7/octave/load_raw.m create mode 100644 codec2/branches/0.7/octave/lpcauto.m create mode 100644 codec2/branches/0.7/octave/lpcpf.m create mode 100644 codec2/branches/0.7/octave/lsp.m create mode 100644 codec2/branches/0.7/octave/lsp_pdf.m create mode 100644 codec2/branches/0.7/octave/lspvar.m create mode 100644 codec2/branches/0.7/octave/lspwarp.m create mode 100644 codec2/branches/0.7/octave/mag_to_phase.m create mode 100644 codec2/branches/0.7/octave/make_hilb.m create mode 100644 codec2/branches/0.7/octave/make_ssbfilt.m create mode 100644 codec2/branches/0.7/octave/mancyfsk.m create mode 100644 codec2/branches/0.7/octave/melstats.m create mode 100644 codec2/branches/0.7/octave/melvq.m create mode 100644 codec2/branches/0.7/octave/mfsk.m create mode 100644 codec2/branches/0.7/octave/newamp.m create mode 100644 codec2/branches/0.7/octave/newamp1_batch.m create mode 100644 codec2/branches/0.7/octave/newamp1_compare.m create mode 100644 codec2/branches/0.7/octave/newamp1_fbf.m create mode 100644 codec2/branches/0.7/octave/newamp_batch.m create mode 100644 codec2/branches/0.7/octave/newamp_fbf.m create mode 100644 codec2/branches/0.7/octave/nf_from_gr.m create mode 100644 codec2/branches/0.7/octave/ofdm_dev.m create mode 100644 codec2/branches/0.7/octave/ofdm_lib.m create mode 100644 codec2/branches/0.7/octave/ofdm_load_const.m create mode 100644 codec2/branches/0.7/octave/ofdm_rs.m create mode 100644 codec2/branches/0.7/octave/ofdm_rx.m create mode 100644 codec2/branches/0.7/octave/ofdm_tx.m create mode 100644 codec2/branches/0.7/octave/oqpsk.m create mode 100644 codec2/branches/0.7/octave/phase.m create mode 100644 codec2/branches/0.7/octave/phase2.m create mode 100644 codec2/branches/0.7/octave/phasesecord.m create mode 100644 codec2/branches/0.7/octave/pitch_test.m create mode 100644 codec2/branches/0.7/octave/pl.m create mode 100644 codec2/branches/0.7/octave/pl2.m create mode 100644 codec2/branches/0.7/octave/plamp.m create mode 100644 codec2/branches/0.7/octave/plinterp.m create mode 100644 codec2/branches/0.7/octave/pllpcpf.m create mode 100644 codec2/branches/0.7/octave/pllsp.m create mode 100644 codec2/branches/0.7/octave/pllspdt.m create mode 100644 codec2/branches/0.7/octave/plnlp.m create mode 100644 codec2/branches/0.7/octave/plot_specgram.m create mode 100644 codec2/branches/0.7/octave/plphase.m create mode 100644 codec2/branches/0.7/octave/plpitch.m create mode 100644 codec2/branches/0.7/octave/plppe.m create mode 100644 codec2/branches/0.7/octave/plsub.m create mode 100644 codec2/branches/0.7/octave/plvoicing.m create mode 100644 codec2/branches/0.7/octave/png.m create mode 100644 codec2/branches/0.7/octave/postfilter.m create mode 100644 codec2/branches/0.7/octave/pulse.m create mode 100644 codec2/branches/0.7/octave/qpsk.m create mode 100644 codec2/branches/0.7/octave/rfdesign.m create mode 100644 codec2/branches/0.7/octave/s_param_rf.m create mode 100644 codec2/branches/0.7/octave/sample_clock_offset.m create mode 100644 codec2/branches/0.7/octave/save_array_c_header.m create mode 100644 codec2/branches/0.7/octave/save_raw.m create mode 100644 codec2/branches/0.7/octave/sd.m create mode 100644 codec2/branches/0.7/octave/spec.m create mode 100644 codec2/branches/0.7/octave/tcohpsk.m create mode 100644 codec2/branches/0.7/octave/telem_upload.py create mode 100644 codec2/branches/0.7/octave/test_cohpsk.m create mode 100644 codec2/branches/0.7/octave/test_cohpsk_ch.m create mode 100644 codec2/branches/0.7/octave/test_dqpsk.m create mode 100644 codec2/branches/0.7/octave/test_dqpsk2.m create mode 100644 codec2/branches/0.7/octave/test_dsss.m create mode 100644 codec2/branches/0.7/octave/test_dsss_pilot.m create mode 100644 codec2/branches/0.7/octave/test_fec.m create mode 100644 codec2/branches/0.7/octave/test_foff.m create mode 100644 codec2/branches/0.7/octave/test_ftrack.m create mode 100644 codec2/branches/0.7/octave/test_ldpc_fsk_lib.m create mode 100644 codec2/branches/0.7/octave/test_ml.m create mode 100644 codec2/branches/0.7/octave/test_pilot.m create mode 100644 codec2/branches/0.7/octave/test_qpsk.m create mode 100644 codec2/branches/0.7/octave/test_qpsk2.m create mode 100644 codec2/branches/0.7/octave/test_qpsk3.m create mode 100644 codec2/branches/0.7/octave/tfdmdv.m create mode 100644 codec2/branches/0.7/octave/tfmfsk.m create mode 100644 codec2/branches/0.7/octave/tfsk.m create mode 100644 codec2/branches/0.7/octave/tfsk_2400a.m create mode 100644 codec2/branches/0.7/octave/tget_spec.m create mode 100644 codec2/branches/0.7/octave/tlinreg.m create mode 100644 codec2/branches/0.7/octave/tnewamp1.m create mode 100644 codec2/branches/0.7/octave/tofdm.m create mode 100644 codec2/branches/0.7/octave/tpapr.m create mode 100644 codec2/branches/0.7/octave/tqpsk.m create mode 100644 codec2/branches/0.7/octave/trellis.m create mode 100644 codec2/branches/0.7/octave/twomixer.m create mode 100644 codec2/branches/0.7/octave/twotone.m create mode 100644 codec2/branches/0.7/octave/twotone1.m create mode 100644 codec2/branches/0.7/octave/tximage.m create mode 100644 codec2/branches/0.7/octave/undersample.m create mode 100644 codec2/branches/0.7/octave/vhf_pa.m create mode 100644 codec2/branches/0.7/octave/vq create mode 100644 codec2/branches/0.7/octave/vq_pager.m create mode 100644 codec2/branches/0.7/octave/xormixer.m create mode 100644 codec2/branches/0.7/octave/yafsk.m create mode 100644 codec2/branches/0.7/raw/b0067.raw create mode 100644 codec2/branches/0.7/raw/cq_ref.raw create mode 100644 codec2/branches/0.7/raw/cross.raw create mode 100644 codec2/branches/0.7/raw/cross_melp2400.raw create mode 100644 codec2/branches/0.7/raw/f2400.raw create mode 100644 codec2/branches/0.7/raw/forig.raw create mode 100644 codec2/branches/0.7/raw/forig_ambe2000.raw create mode 100644 codec2/branches/0.7/raw/forig_g729a.raw create mode 100644 codec2/branches/0.7/raw/forig_gsm13k.raw create mode 100644 codec2/branches/0.7/raw/forig_speex_8k.raw create mode 100644 codec2/branches/0.7/raw/g3plx.raw create mode 100644 codec2/branches/0.7/raw/hts.raw create mode 100644 codec2/branches/0.7/raw/hts1.raw create mode 100644 codec2/branches/0.7/raw/hts1a.raw create mode 100644 codec2/branches/0.7/raw/hts1a_ambe2000.raw create mode 100644 codec2/branches/0.7/raw/hts1a_g729a.raw create mode 100644 codec2/branches/0.7/raw/hts1a_gsm13k.raw create mode 100644 codec2/branches/0.7/raw/hts1a_melp.raw create mode 100644 codec2/branches/0.7/raw/hts1a_speex_8k.raw create mode 100644 codec2/branches/0.7/raw/hts2.raw create mode 100644 codec2/branches/0.7/raw/hts2a.raw create mode 100644 codec2/branches/0.7/raw/hts2a_ambe2000.raw create mode 100644 codec2/branches/0.7/raw/hts2a_g729a.raw create mode 100644 codec2/branches/0.7/raw/hts2a_gsm13k.raw create mode 100644 codec2/branches/0.7/raw/hts2a_melp.raw create mode 100644 codec2/branches/0.7/raw/hts2a_speex_8k.raw create mode 100644 codec2/branches/0.7/raw/k6hx.raw create mode 100644 codec2/branches/0.7/raw/kristoff.raw create mode 100644 codec2/branches/0.7/raw/m2400.raw create mode 100644 codec2/branches/0.7/raw/mmt1.raw create mode 100644 codec2/branches/0.7/raw/mmt1_ambe2000.raw create mode 100644 codec2/branches/0.7/raw/mmt1_g729a.raw create mode 100644 codec2/branches/0.7/raw/mmt1_gsm13k.raw create mode 100644 codec2/branches/0.7/raw/mmt1_speex_8k.raw create mode 100644 codec2/branches/0.7/raw/morig.raw create mode 100644 codec2/branches/0.7/raw/morig_ambe2000.raw create mode 100644 codec2/branches/0.7/raw/morig_g729a.raw create mode 100644 codec2/branches/0.7/raw/morig_gsm13k.raw create mode 100644 codec2/branches/0.7/raw/morig_speex_8k.raw create mode 100644 codec2/branches/0.7/raw/sine1k_2Hz_spread.raw create mode 100644 codec2/branches/0.7/raw/sine1k_2ms_delay_2Hz_spread.raw create mode 100644 codec2/branches/0.7/raw/ve9qrp.raw create mode 100644 codec2/branches/0.7/raw/ve9qrp_10s.raw create mode 100644 codec2/branches/0.7/raw/vk5qi.raw create mode 100755 codec2/branches/0.7/script/menu.sh create mode 100755 codec2/branches/0.7/script/playraw.sh create mode 100755 codec2/branches/0.7/script/raw2wav.sh create mode 100755 codec2/branches/0.7/script/separate_all.sh create mode 100755 codec2/branches/0.7/script/wav2raw.sh create mode 100644 codec2/branches/0.7/src/CMakeLists.txt create mode 100644 codec2/branches/0.7/src/H2064_516_sparse.h create mode 100644 codec2/branches/0.7/src/HRA_112_112.h create mode 100644 codec2/branches/0.7/src/_kiss_fft_guts.h create mode 100644 codec2/branches/0.7/src/ampexp.c create mode 100644 codec2/branches/0.7/src/ampexp.h create mode 100644 codec2/branches/0.7/src/bpf.h create mode 100644 codec2/branches/0.7/src/bpfb.h create mode 100644 codec2/branches/0.7/src/c2dec.c create mode 100644 codec2/branches/0.7/src/c2demo.c create mode 100644 codec2/branches/0.7/src/c2enc.c create mode 100644 codec2/branches/0.7/src/c2sim.c create mode 100644 codec2/branches/0.7/src/codebook.c create mode 100644 codec2/branches/0.7/src/codebook/dlsp1.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp10.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp2.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp3.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp4.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp5.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp6.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp7.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp8.txt create mode 100644 codec2/branches/0.7/src/codebook/dlsp9.txt create mode 100644 codec2/branches/0.7/src/codebook/gecb.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp1.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp10.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp2.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp3.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp4.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp5.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp6.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp7.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp8.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp8910.txt create mode 100644 codec2/branches/0.7/src/codebook/lsp9.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt1-10.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt10.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt3.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt4.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt5.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt6.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt7.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt8.txt create mode 100644 codec2/branches/0.7/src/codebook/lspdt9.txt create mode 100644 codec2/branches/0.7/src/codebook/lspjvm1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspjvm2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspjvm3.txt create mode 100644 codec2/branches/0.7/src/codebook/lspmelvq1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspmelvq2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspmelvq3.txt create mode 100644 codec2/branches/0.7/src/codebook/lspres_bw1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspres_bw2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspres_centre1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspres_centre2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqanssi1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqanssi2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqanssi3.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqanssi4.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqexp1.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqexp2.txt create mode 100644 codec2/branches/0.7/src/codebook/lspvqexp3.txt create mode 100644 codec2/branches/0.7/src/codebook/mel1.txt create mode 100644 codec2/branches/0.7/src/codebook/mel2.txt create mode 100644 codec2/branches/0.7/src/codebook/mel3.txt create mode 100644 codec2/branches/0.7/src/codebook/mel4.txt create mode 100644 codec2/branches/0.7/src/codebook/mel5.txt create mode 100644 codec2/branches/0.7/src/codebook/mel6.txt create mode 100644 codec2/branches/0.7/src/codebook/newamp1_energy_q.txt create mode 100644 codec2/branches/0.7/src/codebook/train_120_1.txt create mode 100644 codec2/branches/0.7/src/codebook/train_120_2.txt create mode 100644 codec2/branches/0.7/src/codebookd.c create mode 100644 codec2/branches/0.7/src/codebookdt.c create mode 100644 codec2/branches/0.7/src/codebookge.c create mode 100644 codec2/branches/0.7/src/codebookjvm.c create mode 100644 codec2/branches/0.7/src/codebooknewamp1.c create mode 100644 codec2/branches/0.7/src/codebooknewamp1_energy.c create mode 100644 codec2/branches/0.7/src/codebookres.c create mode 100644 codec2/branches/0.7/src/codebookvq.c create mode 100644 codec2/branches/0.7/src/codec2.c create mode 100644 codec2/branches/0.7/src/codec2.h create mode 100644 codec2/branches/0.7/src/codec2_cohpsk.h create mode 100644 codec2/branches/0.7/src/codec2_fdmdv.h create mode 100644 codec2/branches/0.7/src/codec2_fft.c create mode 100644 codec2/branches/0.7/src/codec2_fft.h create mode 100644 codec2/branches/0.7/src/codec2_fifo.h create mode 100644 codec2/branches/0.7/src/codec2_fm.h create mode 100644 codec2/branches/0.7/src/codec2_internal.h create mode 100644 codec2/branches/0.7/src/codec2_ofdm.h create mode 100644 codec2/branches/0.7/src/cohpsk.c create mode 100644 codec2/branches/0.7/src/cohpsk_ch.c create mode 100644 codec2/branches/0.7/src/cohpsk_defs.h create mode 100644 codec2/branches/0.7/src/cohpsk_demod.c create mode 100644 codec2/branches/0.7/src/cohpsk_get_test_bits.c create mode 100644 codec2/branches/0.7/src/cohpsk_internal.h create mode 100644 codec2/branches/0.7/src/cohpsk_mod.c create mode 100644 codec2/branches/0.7/src/cohpsk_put_test_bits.c create mode 100644 codec2/branches/0.7/src/comp.h create mode 100644 codec2/branches/0.7/src/comp_prim.h create mode 100644 codec2/branches/0.7/src/defines.h create mode 100644 codec2/branches/0.7/src/drs232.c create mode 100755 codec2/branches/0.7/src/drs232_ldpc.c create mode 100644 codec2/branches/0.7/src/dump.c create mode 100644 codec2/branches/0.7/src/dump.h create mode 100644 codec2/branches/0.7/src/fdmdv.c create mode 100644 codec2/branches/0.7/src/fdmdv_channel.c create mode 100644 codec2/branches/0.7/src/fdmdv_demod.c create mode 100644 codec2/branches/0.7/src/fdmdv_get_test_bits.c create mode 100644 codec2/branches/0.7/src/fdmdv_interleave.c create mode 100644 codec2/branches/0.7/src/fdmdv_internal.h create mode 100644 codec2/branches/0.7/src/fdmdv_mod.c create mode 100644 codec2/branches/0.7/src/fdmdv_put_test_bits.c create mode 100644 codec2/branches/0.7/src/fec_dec.c create mode 100644 codec2/branches/0.7/src/fec_enc.c create mode 100644 codec2/branches/0.7/src/fifo.c create mode 100644 codec2/branches/0.7/src/fm.c create mode 100644 codec2/branches/0.7/src/fm_demod.c create mode 100644 codec2/branches/0.7/src/fm_fir_coeff.h create mode 100644 codec2/branches/0.7/src/fmfsk.c create mode 100644 codec2/branches/0.7/src/fmfsk.h create mode 100644 codec2/branches/0.7/src/fmfsk_demod.c create mode 100644 codec2/branches/0.7/src/fmfsk_mod.c create mode 100755 codec2/branches/0.7/src/fq20.sh create mode 100644 codec2/branches/0.7/src/freedv_api.c create mode 100644 codec2/branches/0.7/src/freedv_api.h create mode 100644 codec2/branches/0.7/src/freedv_api_internal.h create mode 100644 codec2/branches/0.7/src/freedv_data_channel.c create mode 100644 codec2/branches/0.7/src/freedv_data_channel.h create mode 100644 codec2/branches/0.7/src/freedv_rx.c create mode 100644 codec2/branches/0.7/src/freedv_tx.c create mode 100644 codec2/branches/0.7/src/freedv_vhf_framing.c create mode 100644 codec2/branches/0.7/src/freedv_vhf_framing.h create mode 100644 codec2/branches/0.7/src/fsk.c create mode 100644 codec2/branches/0.7/src/fsk.h create mode 100644 codec2/branches/0.7/src/fsk_demod.c create mode 100644 codec2/branches/0.7/src/fsk_get_test_bits.c create mode 100644 codec2/branches/0.7/src/fsk_mod.c create mode 100644 codec2/branches/0.7/src/fsk_put_test_bits.c create mode 100644 codec2/branches/0.7/src/generate_codebook.c create mode 100644 codec2/branches/0.7/src/golay23.c create mode 100644 codec2/branches/0.7/src/golay23.h create mode 100644 codec2/branches/0.7/src/golaydectable.h create mode 100644 codec2/branches/0.7/src/golayenctable.h create mode 100644 codec2/branches/0.7/src/hanning.h create mode 100644 codec2/branches/0.7/src/horus_l2.c create mode 100644 codec2/branches/0.7/src/horus_l2.h create mode 100644 codec2/branches/0.7/src/ht_coeff.h create mode 100644 codec2/branches/0.7/src/insert_errors.c create mode 100644 codec2/branches/0.7/src/interp.c create mode 100644 codec2/branches/0.7/src/interp.h create mode 100644 codec2/branches/0.7/src/kiss_fft.c create mode 100644 codec2/branches/0.7/src/kiss_fft.h create mode 100644 codec2/branches/0.7/src/kiss_fftr.c create mode 100644 codec2/branches/0.7/src/kiss_fftr.h create mode 100644 codec2/branches/0.7/src/ldpc_dec.c create mode 100644 codec2/branches/0.7/src/ldpc_enc.c create mode 100644 codec2/branches/0.7/src/linreg.c create mode 100644 codec2/branches/0.7/src/linreg.h create mode 100755 codec2/branches/0.7/src/listensim.sh create mode 100644 codec2/branches/0.7/src/lpc.c create mode 100644 codec2/branches/0.7/src/lpc.h create mode 100644 codec2/branches/0.7/src/lsp.c create mode 100644 codec2/branches/0.7/src/lsp.h create mode 100644 codec2/branches/0.7/src/machdep.h create mode 100644 codec2/branches/0.7/src/mbest.c create mode 100644 codec2/branches/0.7/src/mbest.h create mode 100644 codec2/branches/0.7/src/modem_probe.c create mode 100644 codec2/branches/0.7/src/modem_probe.h create mode 100644 codec2/branches/0.7/src/modem_stats.c create mode 100644 codec2/branches/0.7/src/modem_stats.h create mode 100644 codec2/branches/0.7/src/mpdecode_core.c create mode 100644 codec2/branches/0.7/src/mpdecode_core.h create mode 100644 codec2/branches/0.7/src/newamp1.c create mode 100644 codec2/branches/0.7/src/newamp1.h create mode 100644 codec2/branches/0.7/src/nlp.c create mode 100644 codec2/branches/0.7/src/nlp.h create mode 100644 codec2/branches/0.7/src/noise_samples.h create mode 100644 codec2/branches/0.7/src/octave.c create mode 100644 codec2/branches/0.7/src/octave.h create mode 100644 codec2/branches/0.7/src/ofdm.c create mode 100644 codec2/branches/0.7/src/ofdm_internal.h create mode 100644 codec2/branches/0.7/src/os.h create mode 100644 codec2/branches/0.7/src/pack.c create mode 100644 codec2/branches/0.7/src/phase.c create mode 100644 codec2/branches/0.7/src/phase.h create mode 100644 codec2/branches/0.7/src/phaseexp.c create mode 100644 codec2/branches/0.7/src/phaseexp.h create mode 100644 codec2/branches/0.7/src/pilot_coeff.h create mode 100644 codec2/branches/0.7/src/pilots_coh.h create mode 100644 codec2/branches/0.7/src/postfilter.c create mode 100644 codec2/branches/0.7/src/postfilter.h create mode 100644 codec2/branches/0.7/src/quantise.c create mode 100644 codec2/branches/0.7/src/quantise.h create mode 100644 codec2/branches/0.7/src/resample.c create mode 100644 codec2/branches/0.7/src/rn.h create mode 100644 codec2/branches/0.7/src/rn_coh.h create mode 100644 codec2/branches/0.7/src/rxdec_coeff.h create mode 100755 codec2/branches/0.7/src/sim.sh create mode 100644 codec2/branches/0.7/src/sine.c create mode 100644 codec2/branches/0.7/src/sine.h create mode 100644 codec2/branches/0.7/src/ssbfilt_coeff.h create mode 100644 codec2/branches/0.7/src/tdma.h create mode 100644 codec2/branches/0.7/src/test_bits.h create mode 100644 codec2/branches/0.7/src/test_bits_coh.h create mode 100644 codec2/branches/0.7/src/test_bits_ofdm.h create mode 100644 codec2/branches/0.7/src/varicode.c create mode 100644 codec2/branches/0.7/src/varicode.h create mode 100644 codec2/branches/0.7/src/varicode_table.h create mode 100644 codec2/branches/0.7/src/vhf_deframe_c2.c create mode 100644 codec2/branches/0.7/src/vhf_frame_c2.c create mode 100644 codec2/branches/0.7/stm32/MENU.txt create mode 100644 codec2/branches/0.7/stm32/Makefile create mode 100644 codec2/branches/0.7/stm32/README.txt create mode 100644 codec2/branches/0.7/stm32/inc/debugblinky.h create mode 100644 codec2/branches/0.7/stm32/inc/gdb_stdio.h create mode 100644 codec2/branches/0.7/stm32/inc/iir_duc.h create mode 100644 codec2/branches/0.7/stm32/inc/iir_tuner.h create mode 100644 codec2/branches/0.7/stm32/inc/menu.h create mode 100644 codec2/branches/0.7/stm32/inc/morse.h create mode 100644 codec2/branches/0.7/stm32/inc/new_i2c.h create mode 100644 codec2/branches/0.7/stm32/inc/sfx.h create mode 100644 codec2/branches/0.7/stm32/inc/si53xx.h create mode 100644 codec2/branches/0.7/stm32/inc/sine.h create mode 100644 codec2/branches/0.7/stm32/inc/sm1000_leds_switches.h create mode 100644 codec2/branches/0.7/stm32/inc/sounds.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_adc.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_adc_tuner.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_dac.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_dacduc.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_usb_vcp.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4_vrom.h create mode 100644 codec2/branches/0.7/stm32/inc/stm32f4xx_conf.h create mode 100644 codec2/branches/0.7/stm32/inc/tm_stm32f4_gpio.h create mode 100644 codec2/branches/0.7/stm32/inc/tm_stm32f4_mco_output.h create mode 100644 codec2/branches/0.7/stm32/inc/tone.h create mode 100644 codec2/branches/0.7/stm32/inc/tot.h create mode 100644 codec2/branches/0.7/stm32/src/adc_rec.c create mode 100644 codec2/branches/0.7/stm32/src/adc_rec_usb.c create mode 100644 codec2/branches/0.7/stm32/src/adc_sd.c create mode 100644 codec2/branches/0.7/stm32/src/adc_sfdr_ut.c create mode 100644 codec2/branches/0.7/stm32/src/adcdac_ut.c create mode 100644 codec2/branches/0.7/stm32/src/codec2_profile.c create mode 100644 codec2/branches/0.7/stm32/src/dac_it.c create mode 100644 codec2/branches/0.7/stm32/src/dac_play.c create mode 100644 codec2/branches/0.7/stm32/src/dac_ut.c create mode 100644 codec2/branches/0.7/stm32/src/dac_ut_fast.c create mode 100644 codec2/branches/0.7/stm32/src/debugblinky.c create mode 100644 codec2/branches/0.7/stm32/src/fast_dac_ut.c create mode 100644 codec2/branches/0.7/stm32/src/fdmdv_dump_rt.c create mode 100644 codec2/branches/0.7/stm32/src/fdmdv_profile.c create mode 100644 codec2/branches/0.7/stm32/src/fft_test.c create mode 100644 codec2/branches/0.7/stm32/src/freedv_rx_profile.c create mode 100644 codec2/branches/0.7/stm32/src/freedv_tx_profile.c create mode 100644 codec2/branches/0.7/stm32/src/gdb_stdio.c create mode 100644 codec2/branches/0.7/stm32/src/iir_duc.c create mode 100644 codec2/branches/0.7/stm32/src/iir_tuner.c create mode 100644 codec2/branches/0.7/stm32/src/init.c create mode 100644 codec2/branches/0.7/stm32/src/mco_ut.c create mode 100644 codec2/branches/0.7/stm32/src/menu.c create mode 100644 codec2/branches/0.7/stm32/src/morse.c create mode 100644 codec2/branches/0.7/stm32/src/new_i2c.c create mode 100644 codec2/branches/0.7/stm32/src/power_ut.c create mode 100644 codec2/branches/0.7/stm32/src/sfx.c create mode 100644 codec2/branches/0.7/stm32/src/si5351_ut.c create mode 100644 codec2/branches/0.7/stm32/src/si53xx.c create mode 100644 codec2/branches/0.7/stm32/src/sine.c create mode 100644 codec2/branches/0.7/stm32/src/sm1000_leds_switches.c create mode 100644 codec2/branches/0.7/stm32/src/sm1000_leds_switches_ut.c create mode 100644 codec2/branches/0.7/stm32/src/sm1000_main.c create mode 100644 codec2/branches/0.7/stm32/src/sm2000_adc_dump.c create mode 100644 codec2/branches/0.7/stm32/src/sm2000_rxdemo.c create mode 100644 codec2/branches/0.7/stm32/src/sm2000_stw.c create mode 100644 codec2/branches/0.7/stm32/src/sounds.c create mode 100644 codec2/branches/0.7/stm32/src/startup_stm32f4xx.s create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_adc.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_adc_tuner.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_dac.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_dacduc.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_dacloduc.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_machdep.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_pwm.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_usb_vcp.c create mode 100644 codec2/branches/0.7/stm32/src/stm32f4_vrom.c create mode 100644 codec2/branches/0.7/stm32/src/system_stm32f4xx.c create mode 100644 codec2/branches/0.7/stm32/src/timer_ut.c create mode 100644 codec2/branches/0.7/stm32/src/tm_stm32f4_gpio.c create mode 100644 codec2/branches/0.7/stm32/src/tm_stm32f4_mco_output.c create mode 100644 codec2/branches/0.7/stm32/src/tone.c create mode 100644 codec2/branches/0.7/stm32/src/tot.c create mode 100644 codec2/branches/0.7/stm32/src/tuner_ut.c create mode 100644 codec2/branches/0.7/stm32/src/usb_vcp_ut.c create mode 100644 codec2/branches/0.7/stm32/src/usb_vsp_ut.c create mode 100644 codec2/branches/0.7/stm32/stlink/elfsym.c create mode 100644 codec2/branches/0.7/stm32/stlink/elfsym.h create mode 100644 codec2/branches/0.7/stm32/stlink/stlink.patch create mode 100644 codec2/branches/0.7/stm32/stm32_flash.ld create mode 100644 codec2/branches/0.7/stm32/stm32_ram.ld create mode 100644 codec2/branches/0.7/stm32/usb_conf/usb_bsp.c create mode 100644 codec2/branches/0.7/stm32/usb_conf/usb_bsp.h create mode 100644 codec2/branches/0.7/stm32/usb_conf/usb_conf.h create mode 100644 codec2/branches/0.7/stm32/usb_conf/usbd_conf.h create mode 100644 codec2/branches/0.7/stm32/usb_conf/usbd_desc.c create mode 100644 codec2/branches/0.7/stm32/usb_conf/usbd_desc.h create mode 100644 codec2/branches/0.7/stm32/usb_conf/usbd_usr.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/cdc/usbd_cdc_core.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/cdc/usbd_cdc_core.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/cdc/usbd_cdc_vcp.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/cdc/usbd_cdc_vcp.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_core.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_core.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_def.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_ioreq.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_ioreq.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_req.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_req.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/core/usbd_usr.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_core.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_core.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_dcd.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_dcd.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_dcd_int.c create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_dcd_int.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_defines.h create mode 100644 codec2/branches/0.7/stm32/usb_lib/otg/usb_regs.h create mode 100644 codec2/branches/0.7/unittest/CMakeLists.txt create mode 100644 codec2/branches/0.7/unittest/Makefile.am create mode 100644 codec2/branches/0.7/unittest/Makefile.in create mode 100644 codec2/branches/0.7/unittest/README create mode 100644 codec2/branches/0.7/unittest/c2validate.c create mode 100644 codec2/branches/0.7/unittest/c2validate.h create mode 100644 codec2/branches/0.7/unittest/create_interleaver.c create mode 100644 codec2/branches/0.7/unittest/de.c create mode 100644 codec2/branches/0.7/unittest/dvdongle2.c create mode 100644 codec2/branches/0.7/unittest/extract.c create mode 100644 codec2/branches/0.7/unittest/fdmdv_mem.c create mode 100644 codec2/branches/0.7/unittest/ge_train.c create mode 100644 codec2/branches/0.7/unittest/genampdata.c create mode 100644 codec2/branches/0.7/unittest/genlsp.c create mode 100644 codec2/branches/0.7/unittest/genphdata.c create mode 100644 codec2/branches/0.7/unittest/genres.c create mode 100644 codec2/branches/0.7/unittest/hts1a.h create mode 100644 codec2/branches/0.7/unittest/hts1a_1300.h create mode 100644 codec2/branches/0.7/unittest/lsp1.txt create mode 100644 codec2/branches/0.7/unittest/lsp10.txt create mode 100644 codec2/branches/0.7/unittest/lsp2.txt create mode 100644 codec2/branches/0.7/unittest/lsp3.txt create mode 100644 codec2/branches/0.7/unittest/lsp4.txt create mode 100644 codec2/branches/0.7/unittest/lsp45678910.txt create mode 100644 codec2/branches/0.7/unittest/lsp5.txt create mode 100644 codec2/branches/0.7/unittest/lsp6.txt create mode 100644 codec2/branches/0.7/unittest/lsp7.txt create mode 100644 codec2/branches/0.7/unittest/lsp8.txt create mode 100644 codec2/branches/0.7/unittest/lsp9.txt create mode 100644 codec2/branches/0.7/unittest/lspd456.txt create mode 100644 codec2/branches/0.7/unittest/lspd678910.txt create mode 100644 codec2/branches/0.7/unittest/lspd78.txt create mode 100644 codec2/branches/0.7/unittest/lspd910.txt create mode 100644 codec2/branches/0.7/unittest/lspjnd5-10.txt create mode 100644 codec2/branches/0.7/unittest/mksine.c create mode 100644 codec2/branches/0.7/unittest/polar2rect.c create mode 100644 codec2/branches/0.7/unittest/pre.c create mode 100644 codec2/branches/0.7/unittest/raw2h.c create mode 100644 codec2/branches/0.7/unittest/run_tests.sh create mode 100644 codec2/branches/0.7/unittest/scalarlsptest.c create mode 100644 codec2/branches/0.7/unittest/sd.c create mode 100644 codec2/branches/0.7/unittest/sd.h create mode 100644 codec2/branches/0.7/unittest/speexlsptest.c create mode 100644 codec2/branches/0.7/unittest/speexnoisesup.c create mode 100644 codec2/branches/0.7/unittest/t16_8.c create mode 100644 codec2/branches/0.7/unittest/t16_8_short.c create mode 100644 codec2/branches/0.7/unittest/t48_8.c create mode 100644 codec2/branches/0.7/unittest/tcodec2.c create mode 100644 codec2/branches/0.7/unittest/tcohpsk.c create mode 100644 codec2/branches/0.7/unittest/tcontphase.c create mode 100644 codec2/branches/0.7/unittest/tdec.c create mode 100644 codec2/branches/0.7/unittest/tdeframer.c create mode 100644 codec2/branches/0.7/unittest/test_cohpsk_ch.c create mode 100644 codec2/branches/0.7/unittest/tfdmdv.c create mode 100644 codec2/branches/0.7/unittest/tfifo.c create mode 100644 codec2/branches/0.7/unittest/tfmfsk.c create mode 100644 codec2/branches/0.7/unittest/tfreedv_data_channel.c create mode 100644 codec2/branches/0.7/unittest/tfsk.c create mode 100644 codec2/branches/0.7/unittest/tinterp.c create mode 100644 codec2/branches/0.7/unittest/tlininterp.c create mode 100644 codec2/branches/0.7/unittest/tlspsens.c create mode 100644 codec2/branches/0.7/unittest/tnewamp1.c create mode 100644 codec2/branches/0.7/unittest/tnlp.c create mode 100644 codec2/branches/0.7/unittest/tofdm.c create mode 100644 codec2/branches/0.7/unittest/tprede.c create mode 100644 codec2/branches/0.7/unittest/tquant.c create mode 100644 codec2/branches/0.7/unittest/tsrc.c create mode 100755 codec2/branches/0.7/unittest/vq_train_jvm.c create mode 100644 codec2/branches/0.7/unittest/vqtrain.c create mode 100644 codec2/branches/0.7/wav/all.wav create mode 100644 codec2/branches/0.7/wav/cross.wav create mode 100644 codec2/branches/0.7/wav/cross_melp2400.wav create mode 100644 codec2/branches/0.7/wav/f2400.wav create mode 100644 codec2/branches/0.7/wav/forig.wav create mode 100644 codec2/branches/0.7/wav/forig_ambe2000.wav create mode 100644 codec2/branches/0.7/wav/forig_speex_8k.wav create mode 100644 codec2/branches/0.7/wav/hts1a.wav create mode 100644 codec2/branches/0.7/wav/hts1a_ambe2000.wav create mode 100644 codec2/branches/0.7/wav/hts1a_c2_v0.1.wav create mode 100644 codec2/branches/0.7/wav/hts1a_c2_v0.1a.wav create mode 100644 codec2/branches/0.7/wav/hts1a_g729a.wav create mode 100644 codec2/branches/0.7/wav/hts1a_lpc10.wav create mode 100644 codec2/branches/0.7/wav/hts1a_speex_8k.wav create mode 100644 codec2/branches/0.7/wav/hts2a.wav create mode 100644 codec2/branches/0.7/wav/hts2a_ambe2000.wav create mode 100644 codec2/branches/0.7/wav/hts2a_c2_v0.1.wav create mode 100644 codec2/branches/0.7/wav/hts2a_c2_v0.1a.wav create mode 100644 codec2/branches/0.7/wav/hts2a_g729a.wav create mode 100644 codec2/branches/0.7/wav/hts2a_lpc10.wav create mode 100644 codec2/branches/0.7/wav/hts2a_speex_8k.wav create mode 100644 codec2/branches/0.7/wav/m2400.wav create mode 100644 codec2/branches/0.7/wav/mmt1.wav create mode 100644 codec2/branches/0.7/wav/mmt1_ambe2000.wav create mode 100644 codec2/branches/0.7/wav/mmt1_c2_v01a.wav create mode 100644 codec2/branches/0.7/wav/mmt1_lpc10.wav create mode 100644 codec2/branches/0.7/wav/mmt1_speex_8k.wav create mode 100644 codec2/branches/0.7/wav/morig.wav create mode 100644 codec2/branches/0.7/wav/morig_ambe2000.wav create mode 100644 codec2/branches/0.7/wav/morig_speex_8k.wav create mode 100644 codec2/branches/0.7/wav/ve9qrp.wav create mode 100644 codec2/branches/0.7/wav/vk5qi.wav create mode 100644 codec2/branches/0.7/wav/x200_ext.wav create mode 100644 codec2/branches/0.7/wav/x200_int.wav create mode 100644 freedv/branches/1.2/RELEASE_NOTES.txt create mode 100644 freedv/branches/1.2/USER_MANUAL.txt create mode 100644 freedv/branches/1.2/freedv-dev/.clang/.gitignore create mode 100644 freedv/branches/1.2/freedv-dev/CMakeLists.txt create mode 100644 freedv/branches/1.2/freedv-dev/COPYING create mode 100644 freedv/branches/1.2/freedv-dev/README.osx create mode 100644 freedv/branches/1.2/freedv-dev/README.txt create mode 100644 freedv/branches/1.2/freedv-dev/RELEASE_NOTES.txt create mode 100644 freedv/branches/1.2/freedv-dev/USER_MANUAL.txt create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildCodec2.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildHamlib.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildPortaudio.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildSamplerate.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildSndfile.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildSpeex.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/BuildWxWidgets.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/FindPortaudio.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/GetDependencies.cmake.in create mode 100644 freedv/branches/1.2/freedv-dev/cmake/MinGW.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/Toolchain-Ubuntu-mingw32.cmake create mode 100644 freedv/branches/1.2/freedv-dev/cmake/config.h.in create mode 100644 freedv/branches/1.2/freedv-dev/cmake/soxconfig.h.in create mode 100644 freedv/branches/1.2/freedv-dev/cmake/version.h.in create mode 100644 freedv/branches/1.2/freedv-dev/contrib/CMakeLists.txt create mode 100644 freedv/branches/1.2/freedv-dev/contrib/LICENSE create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv.desktop create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv.ico create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv.rc create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv128x128.png create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv256x256.png create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv48x48.png create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv64x64.png create mode 100644 freedv/branches/1.2/freedv-dev/contrib/freedv_screenshot.png create mode 100644 freedv/branches/1.2/freedv-dev/credits.txt create mode 100644 freedv/branches/1.2/freedv-dev/db/current create mode 100644 freedv/branches/1.2/freedv-dev/db/format create mode 100644 freedv/branches/1.2/freedv-dev/db/fs-type create mode 100644 freedv/branches/1.2/freedv-dev/db/fsfs.conf create mode 100644 freedv/branches/1.2/freedv-dev/db/min-unpacked-rev create mode 100644 freedv/branches/1.2/freedv-dev/db/rep-cache.db create mode 100644 freedv/branches/1.2/freedv-dev/db/revprops/0/0 create mode 100644 freedv/branches/1.2/freedv-dev/db/revprops/0/1 create mode 100644 freedv/branches/1.2/freedv-dev/db/revs/0/0 create mode 100644 freedv/branches/1.2/freedv-dev/db/revs/0/1 create mode 100644 freedv/branches/1.2/freedv-dev/db/transactions/.gitignore create mode 100644 freedv/branches/1.2/freedv-dev/db/txn-current create mode 100644 freedv/branches/1.2/freedv-dev/db/txn-current-lock create mode 100644 freedv/branches/1.2/freedv-dev/db/txn-protorevs/.gitignore create mode 100644 freedv/branches/1.2/freedv-dev/db/uuid create mode 100644 freedv/branches/1.2/freedv-dev/db/write-lock create mode 100644 freedv/branches/1.2/freedv-dev/debian/changelog create mode 100644 freedv/branches/1.2/freedv-dev/debian/compat create mode 100644 freedv/branches/1.2/freedv-dev/debian/control create mode 100644 freedv/branches/1.2/freedv-dev/debian/copyright create mode 100644 freedv/branches/1.2/freedv-dev/debian/docs create mode 100644 freedv/branches/1.2/freedv-dev/debian/format create mode 100755 freedv/branches/1.2/freedv-dev/debian/rules create mode 100644 freedv/branches/1.2/freedv-dev/script/spot.sh create mode 100644 freedv/branches/1.2/freedv-dev/src/CMakeLists.txt create mode 100644 freedv/branches/1.2/freedv-dev/src/Makefile.win32 create mode 100644 freedv/branches/1.2/freedv-dev/src/afreedvplugin.c create mode 100644 freedv/branches/1.2/freedv-dev/src/comp.h create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_audiooptions.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_audiooptions.h create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_filter.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_filter.h create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_options.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_options.h create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_plugin.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_plugin.h create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_ptt.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/dlg_ptt.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_defines.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_main.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_main.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_pa_wrapper.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_pa_wrapper.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_scalar.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_scalar.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_scatter.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_scatter.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_spectrum.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_spectrum.h create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_waterfall.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/fdmdv2_plot_waterfall.h create mode 100644 freedv/branches/1.2/freedv-dev/src/freedv.icns create mode 100644 freedv/branches/1.2/freedv-dev/src/hamlib.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/hamlib.h create mode 100644 freedv/branches/1.2/freedv-dev/src/info.plist create mode 100644 freedv/branches/1.2/freedv-dev/src/serialport.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/serialport.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/band.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/biquad.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/biquad.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/biquads.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/effects.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/effects.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/effects_i.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/formats_i.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/libsox.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/sox.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/sox_i.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/soxomp.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/util.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/xmalloc.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox/xmalloc.h create mode 100644 freedv/branches/1.2/freedv-dev/src/sox_biquad.c create mode 100644 freedv/branches/1.2/freedv-dev/src/sox_biquad.h create mode 100644 freedv/branches/1.2/freedv-dev/src/topFrame.cpp create mode 100644 freedv/branches/1.2/freedv-dev/src/topFrame.h create mode 100644 freedv/branches/1.2/src/serialport.cpp create mode 100644 freedv/branches/1.2/src/serialport.h create mode 100644 freedv/tags/1.2.2/.clang/.gitignore create mode 100644 freedv/tags/1.2.2/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/COPYING create mode 100644 freedv/tags/1.2.2/README.osx create mode 100644 freedv/tags/1.2.2/README.txt create mode 100644 freedv/tags/1.2.2/RELEASE_NOTES.txt create mode 100644 freedv/tags/1.2.2/USER_MANUAL.txt create mode 100644 freedv/tags/1.2.2/cmake/BuildCodec2.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildHamlib.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildPortaudio.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildSamplerate.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildSndfile.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildSpeex.cmake create mode 100644 freedv/tags/1.2.2/cmake/BuildWxWidgets.cmake create mode 100644 freedv/tags/1.2.2/cmake/FindPortaudio.cmake create mode 100644 freedv/tags/1.2.2/cmake/GetDependencies.cmake.in create mode 100644 freedv/tags/1.2.2/cmake/MinGW.cmake create mode 100644 freedv/tags/1.2.2/cmake/Toolchain-Ubuntu-mingw32.cmake create mode 100644 freedv/tags/1.2.2/cmake/config.h.in create mode 100644 freedv/tags/1.2.2/cmake/soxconfig.h.in create mode 100644 freedv/tags/1.2.2/cmake/version.h.in create mode 100644 freedv/tags/1.2.2/contrib/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/contrib/LICENSE create mode 100644 freedv/tags/1.2.2/contrib/freedv.desktop create mode 100644 freedv/tags/1.2.2/contrib/freedv.ico create mode 100644 freedv/tags/1.2.2/contrib/freedv.rc create mode 100644 freedv/tags/1.2.2/contrib/freedv128x128.png create mode 100644 freedv/tags/1.2.2/contrib/freedv256x256.png create mode 100644 freedv/tags/1.2.2/contrib/freedv48x48.png create mode 100644 freedv/tags/1.2.2/contrib/freedv64x64.png create mode 100644 freedv/tags/1.2.2/contrib/freedv_screenshot.png create mode 100644 freedv/tags/1.2.2/credits.txt create mode 100644 freedv/tags/1.2.2/db/current create mode 100644 freedv/tags/1.2.2/db/format create mode 100644 freedv/tags/1.2.2/db/fs-type create mode 100644 freedv/tags/1.2.2/db/fsfs.conf create mode 100644 freedv/tags/1.2.2/db/min-unpacked-rev create mode 100644 freedv/tags/1.2.2/db/rep-cache.db create mode 100644 freedv/tags/1.2.2/db/revprops/0/0 create mode 100644 freedv/tags/1.2.2/db/revprops/0/1 create mode 100644 freedv/tags/1.2.2/db/revs/0/0 create mode 100644 freedv/tags/1.2.2/db/revs/0/1 create mode 100644 freedv/tags/1.2.2/db/transactions/.gitignore create mode 100644 freedv/tags/1.2.2/db/txn-current create mode 100644 freedv/tags/1.2.2/db/txn-current-lock create mode 100644 freedv/tags/1.2.2/db/txn-protorevs/.gitignore create mode 100644 freedv/tags/1.2.2/db/uuid create mode 100644 freedv/tags/1.2.2/db/write-lock create mode 100644 freedv/tags/1.2.2/debian/changelog create mode 100644 freedv/tags/1.2.2/debian/compat create mode 100644 freedv/tags/1.2.2/debian/control create mode 100644 freedv/tags/1.2.2/debian/copyright create mode 100644 freedv/tags/1.2.2/debian/docs create mode 100644 freedv/tags/1.2.2/debian/format create mode 100755 freedv/tags/1.2.2/debian/rules create mode 100644 freedv/tags/1.2.2/freedv-dev/.clang/.gitignore create mode 100644 freedv/tags/1.2.2/freedv-dev/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/COPYING create mode 100644 freedv/tags/1.2.2/freedv-dev/README.osx create mode 100644 freedv/tags/1.2.2/freedv-dev/README.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/RELEASE_NOTES.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/USER_MANUAL.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildCodec2.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildHamlib.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildPortaudio.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildSamplerate.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildSndfile.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildSpeex.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/BuildWxWidgets.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/FindPortaudio.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/GetDependencies.cmake.in create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/MinGW.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/Toolchain-Ubuntu-mingw32.cmake create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/config.h.in create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/soxconfig.h.in create mode 100644 freedv/tags/1.2.2/freedv-dev/cmake/version.h.in create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/LICENSE create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv.desktop create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv.ico create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv.rc create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv128x128.png create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv256x256.png create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv48x48.png create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv64x64.png create mode 100644 freedv/tags/1.2.2/freedv-dev/contrib/freedv_screenshot.png create mode 100644 freedv/tags/1.2.2/freedv-dev/credits.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/db/current create mode 100644 freedv/tags/1.2.2/freedv-dev/db/format create mode 100644 freedv/tags/1.2.2/freedv-dev/db/fs-type create mode 100644 freedv/tags/1.2.2/freedv-dev/db/fsfs.conf create mode 100644 freedv/tags/1.2.2/freedv-dev/db/min-unpacked-rev create mode 100644 freedv/tags/1.2.2/freedv-dev/db/rep-cache.db create mode 100644 freedv/tags/1.2.2/freedv-dev/db/revprops/0/0 create mode 100644 freedv/tags/1.2.2/freedv-dev/db/revprops/0/1 create mode 100644 freedv/tags/1.2.2/freedv-dev/db/revs/0/0 create mode 100644 freedv/tags/1.2.2/freedv-dev/db/revs/0/1 create mode 100644 freedv/tags/1.2.2/freedv-dev/db/transactions/.gitignore create mode 100644 freedv/tags/1.2.2/freedv-dev/db/txn-current create mode 100644 freedv/tags/1.2.2/freedv-dev/db/txn-current-lock create mode 100644 freedv/tags/1.2.2/freedv-dev/db/txn-protorevs/.gitignore create mode 100644 freedv/tags/1.2.2/freedv-dev/db/uuid create mode 100644 freedv/tags/1.2.2/freedv-dev/db/write-lock create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/changelog create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/compat create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/control create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/copyright create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/docs create mode 100644 freedv/tags/1.2.2/freedv-dev/debian/format create mode 100755 freedv/tags/1.2.2/freedv-dev/debian/rules create mode 100644 freedv/tags/1.2.2/freedv-dev/script/spot.sh create mode 100644 freedv/tags/1.2.2/freedv-dev/src/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/freedv-dev/src/Makefile.win32 create mode 100644 freedv/tags/1.2.2/freedv-dev/src/afreedvplugin.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/comp.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_audiooptions.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_audiooptions.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_filter.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_filter.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_options.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_options.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_plugin.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_plugin.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_ptt.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/dlg_ptt.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_defines.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_main.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_main.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_pa_wrapper.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_pa_wrapper.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_scalar.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_scalar.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_scatter.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_scatter.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_spectrum.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_spectrum.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_waterfall.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/fdmdv2_plot_waterfall.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/freedv.icns create mode 100644 freedv/tags/1.2.2/freedv-dev/src/hamlib.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/hamlib.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/info.plist create mode 100644 freedv/tags/1.2.2/freedv-dev/src/serialport.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/serialport.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/band.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/biquad.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/biquad.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/biquads.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/effects.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/effects.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/effects_i.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/formats_i.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/libsox.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/sox.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/sox_i.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/soxomp.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/util.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/xmalloc.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox/xmalloc.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox_biquad.c create mode 100644 freedv/tags/1.2.2/freedv-dev/src/sox_biquad.h create mode 100644 freedv/tags/1.2.2/freedv-dev/src/topFrame.cpp create mode 100644 freedv/tags/1.2.2/freedv-dev/src/topFrame.h create mode 100644 freedv/tags/1.2.2/script/spot.sh create mode 100644 freedv/tags/1.2.2/src/CMakeLists.txt create mode 100644 freedv/tags/1.2.2/src/Makefile.win32 create mode 100644 freedv/tags/1.2.2/src/afreedvplugin.c create mode 100644 freedv/tags/1.2.2/src/comp.h create mode 100644 freedv/tags/1.2.2/src/dlg_audiooptions.cpp create mode 100644 freedv/tags/1.2.2/src/dlg_audiooptions.h create mode 100644 freedv/tags/1.2.2/src/dlg_filter.cpp create mode 100644 freedv/tags/1.2.2/src/dlg_filter.h create mode 100644 freedv/tags/1.2.2/src/dlg_options.cpp create mode 100644 freedv/tags/1.2.2/src/dlg_options.h create mode 100644 freedv/tags/1.2.2/src/dlg_plugin.cpp create mode 100644 freedv/tags/1.2.2/src/dlg_plugin.h create mode 100644 freedv/tags/1.2.2/src/dlg_ptt.cpp create mode 100644 freedv/tags/1.2.2/src/dlg_ptt.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_defines.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_main.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_main.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_pa_wrapper.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_pa_wrapper.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_scalar.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_scalar.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_scatter.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_scatter.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_spectrum.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_spectrum.h create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_waterfall.cpp create mode 100644 freedv/tags/1.2.2/src/fdmdv2_plot_waterfall.h create mode 100644 freedv/tags/1.2.2/src/freedv.icns create mode 100644 freedv/tags/1.2.2/src/hamlib.cpp create mode 100644 freedv/tags/1.2.2/src/hamlib.h create mode 100644 freedv/tags/1.2.2/src/info.plist create mode 100644 freedv/tags/1.2.2/src/serialport.cpp create mode 100644 freedv/tags/1.2.2/src/serialport.h create mode 100644 freedv/tags/1.2.2/src/sox/band.h create mode 100644 freedv/tags/1.2.2/src/sox/biquad.c create mode 100644 freedv/tags/1.2.2/src/sox/biquad.h create mode 100644 freedv/tags/1.2.2/src/sox/biquads.c create mode 100644 freedv/tags/1.2.2/src/sox/effects.c create mode 100644 freedv/tags/1.2.2/src/sox/effects.h create mode 100644 freedv/tags/1.2.2/src/sox/effects_i.c create mode 100644 freedv/tags/1.2.2/src/sox/formats_i.c create mode 100644 freedv/tags/1.2.2/src/sox/libsox.c create mode 100644 freedv/tags/1.2.2/src/sox/sox.h create mode 100644 freedv/tags/1.2.2/src/sox/sox_i.h create mode 100644 freedv/tags/1.2.2/src/sox/soxomp.h create mode 100644 freedv/tags/1.2.2/src/sox/util.h create mode 100644 freedv/tags/1.2.2/src/sox/xmalloc.c create mode 100644 freedv/tags/1.2.2/src/sox/xmalloc.h create mode 100644 freedv/tags/1.2.2/src/sox_biquad.c create mode 100644 freedv/tags/1.2.2/src/sox_biquad.h create mode 100644 freedv/tags/1.2.2/src/topFrame.cpp create mode 100644 freedv/tags/1.2.2/src/topFrame.h diff --git a/codec2-dev/CMakeLists.txt b/codec2-dev/CMakeLists.txt index ebf8fff1..80f74112 100644 --- a/codec2-dev/CMakeLists.txt +++ b/codec2-dev/CMakeLists.txt @@ -35,7 +35,7 @@ endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") # file at some point. # set(CODEC2_VERSION_MAJOR 0) -set(CODEC2_VERSION_MINOR 6) +set(CODEC2_VERSION_MINOR 7) # Set to patch level if needed, otherwise leave FALSE. set(CODEC2_VERSION_PATCH FALSE) set(CODEC2_VERSION "${CODEC2_VERSION_MAJOR}.${CODEC2_VERSION_MINOR}") diff --git a/codec2/branches/0.7/CMakeLists.txt b/codec2/branches/0.7/CMakeLists.txt new file mode 100644 index 00000000..45cc8873 --- /dev/null +++ b/codec2/branches/0.7/CMakeLists.txt @@ -0,0 +1,244 @@ +# +# Codec2 - Next-Generation Digital Voice for Two-Way Radio +# +# CMake configuration contributed by Richard Shaw (KF5OIM) +# Please report questions, comments, problems, or patches to the freetel +# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2 +# +project(codec2 C) + +cmake_minimum_required(VERSION 2.8) + +include(GNUInstallDirs) +mark_as_advanced(CLEAR + CMAKE_INSTALL_BINDIR + CMAKE_INSTALL_INCLUDEDIR + CMAKE_INSTALL_LIBDIR +) + +# +# Prevent in-source builds +# If an in-source build is attempted, you will still need to clean up a few +# files manually. +# +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) +if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not " + "allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a " + "separate build directory and run cmake from there.") +endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + + +# +# Set project version information. This should probably be done via external +# file at some point. +# +set(CODEC2_VERSION_MAJOR 0) +set(CODEC2_VERSION_MINOR 7) +# Set to patch level if needed, otherwise leave FALSE. +set(CODEC2_VERSION_PATCH FALSE) +set(CODEC2_VERSION "${CODEC2_VERSION_MAJOR}.${CODEC2_VERSION_MINOR}") +# Patch level version bumps should not change API/ABI. +set(SOVERSION "${CODEC2_VERSION_MAJOR}.${CODEC2_VERSION_MINOR}") +if(CODEC2_VERSION_PATCH) + set(CODEC2_VERSION "${CODEC2_VERSION}.${CODEC2_VERSION_PATCH}") +endif() +message(STATUS "codec2 version: ${CODEC2_VERSION}") + +# Set default build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") +endif() + +# Set default C++ flags. +include(CheckCCompilerFlag) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -g -O3") +CHECK_C_COMPILER_FLAG("-std=gnu11" COMPILER_SUPPORTS_GNU11) +if(CMAKE_C_STANDARD_COMPUTED_DEFAULT EQUAL "90") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +endif() +# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") + +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS}") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS}") + +# -fPIC is implied on MinGW... +if(NOT WIN32) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") +endif() + +message(STATUS "Build type is: " ${CMAKE_BUILD_TYPE}) +string(TOUPPER ${CMAKE_BUILD_TYPE} _FLAGS) +if(NOT _FLAGS STREQUAL "NONE") + set(BUILD_FLAGS "${CMAKE_C_FLAGS_${_FLAGS}}") +endif() +message(STATUS "Compiler Flags: " ${BUILD_FLAGS}) + +# +# Setup Windows/MinGW specifics here. +# +if(MINGW) + message(STATUS "System is MinGW.") +endif(MINGW) + + +# +# Find the svn revision if this is a working copy. +# WORK IN PROGRESS +# Works ok if it is a working copy but errors out if not. +# +#find_package(Subversion) +#if(Subversion_FOUND) +# Subversion_WC_INFO(${CMAKE_CURRENT_SOURCE_DIR} CODEC2) +# message(STATUS "codec2 svn revision: ${CODEC2_WC_REVISION}") +#else(SUBVERSION_FOUND) +# message(WARNING "Subversion not found. Can not determine svn revision.") +#endif(SUBVERSION_FOUND) + + +# +# Default options +# +option(BUILD_SHARED_LIBS + "Build shared library. Set to OFF for static library." ON) +# Unittest should be on for dev builds and off for releases. +if(CMAKE_BUILD_TYPE MATCHES "Release") + option(UNITTEST "Build unittest binaries." OFF) +else() + option(UNITTEST "Build unittest binaries." ON) +endif() +option(INSTALL_EXAMPLES "Install example code." OFF) +if(INSTALL_EXAMPLES) + install(DIRECTORY octave raw script wav + USE_SOURCE_PERMISSIONS + DESTINATION ${CMAKE_INSTALL_DATADIR}/codec2) +endif() + + +# Math library is automatic on windows +if(UNIX) + set(CMAKE_REQUIRED_INCLUDES math.h) + set(CMAKE_REQUIRED_LIBRARIES m) +endif(UNIX) + +include(CheckIncludeFiles) +check_include_files("stdlib.h" HAVE_STDLIB_H) +check_include_files("string.h" HAVE_STRING_H) + +include(CheckFunctionExists) +check_function_exists(floor HAVE_FLOOR) +check_function_exists(ceil HAVE_CEIL) +check_function_exists(pow HAVE_POW) +check_function_exists(sqrt HAVE_SQRT) +check_function_exists(sin HAVE_SIN) +check_function_exists(cos HAVE_COS) +check_function_exists(atan2 HAVE_ATAN2) +check_function_exists(log10 HAVE_LOG10) +check_function_exists(round HAVE_ROUND) +check_function_exists(getopt HAVE_GETOPT) + +configure_file ("${PROJECT_SOURCE_DIR}/cmake/config.h.in" + "${PROJECT_BINARY_DIR}/config.h" ) +include_directories(${PROJECT_BINARY_DIR}) + +# CMake Package setup +#include(CMakePackageConfigHelpers) +#configure_package_config_file(cmake/codec2-config.cmake.in +# ${CMAKE_CURRENT_BINARY_DIR}/codec2-config.cmake +# INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/codec2 +# PATH_VARS CMAKE_INSTALL_INCLUDEDIR +#) + +# +# codec2 library +# +add_subdirectory(src) + +if(UNITTEST) + # Pthread Library + find_package(Threads REQUIRED) + message(STATUS "Threads library flags: ${CMAKE_THREAD_LIBS_INIT}") + + # + # Find speex library + # + message(STATUS "Looking for Speex DSP library.") + find_path(SPEEXDSP_INCLUDE_DIR speex/speex.h) + find_library(SPEEXDSP_LIBRARY speexdsp) + message(STATUS " Speex DSP headers: ${SPEEXDSP_INCLUDE_DIR}") + message(STATUS " Speex DSP library: ${SPEEXDSP_LIBRARY}") + if(NOT SPEEXDSP_INCLUDE_DIR AND NOT SPEEXDSP_LIBRARY) + message(FATAL_ERROR "Speex DSP library not found!") + endif() + + # + # Samplerate Library + # + message(STATUS "Looking for samplerate...") + find_library(LIBSAMPLERATE samplerate) + find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h) + message(STATUS " samplerate headers: ${LIBSAMPLERATE_INCLUDE_DIR}") + message(STATUS " samplerate library: ${LIBSAMPLERATE}") + if(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR) + list(APPEND FREEDV_LINK_LIBS ${CMAKE_REQUIRED_LIBRARIES}) + include_directories(${LIBSAMPLERATE_INCLUDE_DIR}) + else(LIBSTAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR) + message(FATAL_ERROR "samplerate library not found. +On Linux systems try installing: + samplerate-devel (RPM based systems) + libsamplerate-dev (DEB based systems)") + endif(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR) + + add_subdirectory(unittest) +endif(UNITTEST) + +# +# Cpack NSIS installer configuration for Windows. +# See: http://nsis.sourceforge.net/Download +# +# *nix systems should use "make install" and/or appropriate +# distribution packaging tools. +# +if(WIN32) + # Detect if we're doing a 32-bit or 64-bit windows build. + if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(CMAKE_CL_64 TRUE) + endif() + configure_file(cmake/GetDependencies.cmake.in cmake/GetDependencies.cmake + @ONLY + ) + install(SCRIPT ${CMAKE_BINARY_DIR}/cmake/GetDependencies.cmake) + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Next-Generation Digital Voice for Two-Way Radio") + set(CPACK_PACKAGE_VENDOR "CMake") + set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") + set(CPACK_PACKAGE_VERSION_MAJOR ${CODEC2_VERSION_MAJOR}) + set(CPACK_PACKAGE_VERSION_MINOR ${CODEC2_VERSION_MINOR}) + if(CODEC2_VERSION_PATCH) + set(CPACK_PACKAGE_VERSION_PATCH ${CODEC2_VERSION_PATCH}) + else() + set(CPACK_PACKAGE_VERSION_PATCH 0) + endif() + set(CPACK_PACKAGE_INSTALL_DIRECTORY "Codec2") + set(CPACK_CREATE_DESKTOP_LINKS "") + set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}") + set(CPACK_NSIS_URL_INFO_ABOUT "http://codec2.org") + set(CPACK_NSIS_MODIFY_PATH ON) + include(CPack) +endif(WIN32) + +######################################################################## +# Create Pkg Config File +######################################################################## +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/codec2.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/codec2.pc + @ONLY +) + +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/codec2.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + COMPONENT "codec2_devel" +) diff --git a/codec2/branches/0.7/COPYING b/codec2/branches/0.7/COPYING new file mode 100644 index 00000000..cc40a468 --- /dev/null +++ b/codec2/branches/0.7/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see + . + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/codec2/branches/0.7/INSTALL b/codec2/branches/0.7/INSTALL new file mode 100644 index 00000000..bcdcf4c0 --- /dev/null +++ b/codec2/branches/0.7/INSTALL @@ -0,0 +1,52 @@ +========================== + Building and Installing +========================== + +NOTES: + - Builds against system libraries by default. + - Has NSIS packaing support for Windows (WIN32) targets. *nix systems should + rely on 'make install' as the packages (RPM & DEB) created by CPack are + questionable. + +To compile codec2, the packages build-essential and cmake are required. +If they are not installed, at a command prompt, type + +$ sudo apt-get install build-essential cmake + +To test the cmake build make a directory anywhere underneath (or outside of) +the source directory. + +Linux command line example: + +$ cd /path/to/codec2 +$ mkdir build_linux +$ cd build_linux +$ cmake ../ + +Install prefix defaults to /usr/local, use CMAKE_INSTALL_PREFIX to override. + +(if no errors) +$ make +(as root) +$ make install + +===================== + Windows +===================== + +Unlike FreeDV (fdmdv2), codec2 is not currently provided as a separate +installer, instead the windows version uses a static build of codec2. + +Additionally, while MSYS2+MinGW should work, windows builds are produces by +cross compiling from linux. + +Install MinGW & the mysys shell + + pwd -W prints true Win32 directory + + I also installed emacs, "tortise svn", and "cmake", and built and installed speex + +$ cd codec2-dev +$ mkdir build_win32 +$ cd build_win32 +$ cmake -DSPEEXDSP_INCLUDE_DIR=/usr/local/include/ -G "MSYS Makefiles" .. +$ make +$ make package diff --git a/codec2/branches/0.7/README b/codec2/branches/0.7/README new file mode 100644 index 00000000..7f9d8315 --- /dev/null +++ b/codec2/branches/0.7/README @@ -0,0 +1,157 @@ +Codec 2 README +-------------- + +Codec 2 is an open source (LGPL 2.1) low bit rate speech codec: + + http://rowetel.com/codec2.html + +Also included: + + + FDMDV modem (README_fdmdv.txt) for HF channels + + Coherent PSK (cohpsk) for HF channels + + FSK modem (README_fsk.txt) for VHF channels + + an OFDM modem for HF channels (ofdm) + + the FreeDV API - a library for embedding FreeDV in other programs + +SVN Repository +-------------- + +Check out the latest (development branch) code using: + + $ svn co https://svn.code.sf.net/p/freetel/code/codec2-dev codec2-dev + +There are unauthorised 3rd party GIT mirrors of Codec 2. + + GIT IS NOT SUPPORTED!!! + +All patches, support questions etc, need to be against the SVN +repository above. + +Quickstart +---------- + +Also see INSTALL for more general building and installing instructions. + +1/ Listen to Codec 2: + + $ cd codec2-dev + $ mkdir build_linux + $ cd build_linux + $ cmake .. + $ make + $ ./src/c2demo ../raw/hts1a.raw hts1a_c2.raw + $ play -t raw -r 8000 -e signed-integer -b 16 ../raw/hts1a.raw + $ play -t raw -r 8000 -e signed-integer -b 16 ./hts1a_c2.raw + +2/ Compress, Decompress and then play a file: + + using 2400 bps bit rate encoding + + $ ./src/c2enc 2400 ../raw/hts1a.raw hts1a_c2.bit + $ ./src/c2dec 2400 hts1a_c2.bit hts1a_c2_2400.raw + + which can be played with + + $ play -t raw -r 8000 -e signed-integer -b 16 ./hts1a_c2_2400.raw + + using 700 bps bit rate encoding + + $ ./src/c2enc 700 ../raw/hts1a.raw hts1a_c2.bit + $ ./src/c2dec 700 hts1a_c2.bit hts1a_c2_700.raw + + which can be played with + + $ play -t raw -r 8000 -e signed-integer -b 16 ./hts1a_c2_700.raw + +3/ Same thing with pipes: + + $ ./src/c2enc 1300 ../raw/hts1a.raw - | ./src/c2dec 1300 - - | play -t raw -r 8000 -s -2 - + +Embedded FreeDV API +------------------- + +See freedv_api.h and freedv_api.c, and the demo programs freedv_tx & +freedv_rx. Quickstart: + + $ ./freedv_tx 1600 ../../raw/hts1.raw - | ./freedv_rx 1600 - - | play -t raw -r 8000 -s -2 -q - + $ cat freedv_rx_log.txt + +Programs +-------- + +1/ c2demo encodes a file of speech samples, then decodes them and +saves the result. + +2/ c2enc encodes a file of speech samples to a compressed file of +encoded bits. + +3/ c2dec decodes a compressed file of bits to a file of speech +samples. + +4/ c2sim is a simulation/development version of Codec 2. It allows +selective use of the various Codec 2 algorithms. For example +switching phase modelling or LSP quantisation on and off. + +Debugging +--------- + +1/ To compile with debug symbols for using gdb: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ CFLAGS=-g cmake .. + $ make + +2/ For dump file support: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ CFLAGS=-DDUMP cmake .. + $ make + +Building Unit Tests +------------------- + +The unittests are no longer built by default. They require +libsamplerate and Speex. + +To build them: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ cmake -DCMAKE_BUILD_TYPE=Debug .. + $ make + +Directories +----------- + + cmake - cmake support files + octave - Octave scripts used to support development + script - shell scripts for playing and converting raw files + src - C source code for Codec 2, FDMDV modem, COHPSK modem, FreeDV API + raw - speech files in raw format (16 bits signed linear 8 kHz) + stm32 - STM32F4 microcontroller and SM1000 FreeDV Adaptor + unittest - unit test source code + wav - speech files in wave file format + +Octave Packages +--------------- + +To run the Octave scripts the following libraries are required: + +Package Name | Version | Installation directory +--------------+---------+----------------------- + control *| 2.6.2 | /usr/share/octave/packages/control-2.6.2 + general *| 1.3.4 | /usr/share/octave/packages/general-1.3.4 + parallel *| 2.2.0 | /usr/share/octave/packages/parallel-2.2.0 + plot *| 1.1.0 | /usr/share/octave/packages/plot-1.1.0 + signal *| 1.2.2 | /usr/share/octave/packages/signal-1.2.2 + specfun *| 1.1.0 | /usr/share/octave/packages/specfun-1.1.0 + +These can be installed using your systems package management system or +the Octave package management system. The version number of each +package is not important. + diff --git a/codec2/branches/0.7/README_fdmdv.txt b/codec2/branches/0.7/README_fdmdv.txt new file mode 100644 index 00000000..eb0c0dff --- /dev/null +++ b/codec2/branches/0.7/README_fdmdv.txt @@ -0,0 +1,201 @@ + +README_fdmdv.txt +David Rowe +Created March 2012 + +Introduction +------------ + +A 1400 bit/s (nominal) Frequency Division Multiplexed Digital Voice +(FDMDV) modem based on [1]. Used for digital audio over HF SSB. + +The FDMDV modem was first implemented in GNU Octave, then ported to C. +Algorithm development is generally easier in Octave, but for real time +work we need the C version. Automated units tests ensure the +operation of the Octave and C versions are identical. + +Quickstart +---------- + +Built as part of codec2-dev, see README for build instructions. + +1. Generate some test bits and modulate them: + + $ ./fdmdv_get_test_bits test.c2 1400 + $ ./fdmdv_mod test.c2 test.raw + $ play -r 8000 -s -2 test.raw + +2. Two seconds of test frame data modulated and sent out of sound device: + + $ ./fdmdv_get_test_bits - 2800 | ./fdmdv_mod - - | play -t raw -r 8000 -s -2 - + +3. Send 14000 modulated bits (10 seconds) to the demod and count errors: + + $ ./fdmdv_get_test_bits - 14000 | ./fdmdv_mod - - | ./fdmdv_demod - - 14 demod_dump.txt | ./fdmdv_put_test_bits - + + Use Octave to look at plots of 1 second (1400 bits) of modem operation: + + $ cd ../octave + $ octave + octave:1> fdmdv_demod_c("../src/demod_dump.txt",1400) + +4. Run Octave simulation of entire modem and AWGN channel: + + $ cd ../octave + $ octave + octave:1> fdmdv_ut + +5. NOTE: If you would like to play modem samples over the air please + convert the 8 kHz samples to 48 kHz. Many PC sound cards have + wildly inaccurate sample clock rates when set to 8 kHz, but seem to + perform OK when set for 48 kHz. If playing and recording files you + can use the sox utility: + + $ sox -r 8000 -s -2 modem_sample_8kHz.raw -r 48000 modem_sample_48kHz.wav + + For real time applications, the fdmdv.[ch] library includes functions to + convert between 48 and 8 kHz sample rates. + +6. Send 20 seconds at 2000 bit/s (20 carriers) to demod and count errors: + + $ ./fdmdv_get_test_bits - 20000 20 | ./fdmdv_mod - - 20 | ./fdmdv_demod - - 20 | ./fdmdv_put_test_bits - 20 + +References +---------- + +[1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf +[2] http://n1su.com/fdmdv/ +[3] http://www.rowetel.com/blog/?p=2433 "Testing a FDMDV Modem" +[4] http://www.rowetel.com/blog/?p=2458 "FDMDV Modem Page" on David's web site + +C Code +------ + +src/fdmdv_mod.c - C version of modulator that takes a file of bits and + converts it to a raw file of modulated samples. + +src/fdmdv_demod.c - C version of demodulator that takes a raw file of + modulated samples and outputs a file of bits. + Optionally dumps demod states to a text file which + can be plotted using the Octave script + fdmdv_demod_c.m + +src/fdmdv.h - Header file that exposes FDMDV C API functions. Include + this file in your application program. + +src/fdmdv.c - C functions that implement the FDMDV modem. + +src/fdmdv-internal.h - internal states and constants for FDMDV modem, + shouldn't be exposed to application program. + + +unittest/tfdmdv.c - Used to conjunction with unittest/tfdmdv.m to + automatically test C FDMDV functions against + Octave versions. + +Octave Scripts +-------------- + +(Note these require some Octave packages to be installed, see +octave/README.txt). + +fdmdv.m - Functions and variables that implement the Octave version of + the FDMDV modem. + +fdmdv_ut.m - Unit test for fdmdv Octave code, useful while + developing algorithm. Includes tx/rx plus basic channel + simulation. + + Typical run: + + octave:6> fdmdv_ut + Eb/No (meas): 7.30 (8.29) dB + bits........: 2464 + errors......: 20 + BER.........: 0.0081 + PAPR........: 13.54 dB + SNR.........: 4.0 dB + + It also outputs lots of nice plots that show the + operation of the modem. + + For a 1400 bit/s DQPSK modem we expect about 1% BER for + Eb/No = 7.3dB, which corresponds to SNR = 4dB (3kHz + noise BW). The extra dB of measured power is due to the + DBPSK pilot. Currently the noise generation code + doesn't take the pilot power into account, so in this + example the real SNR is actually 5dB. + +fdmdv_mod.m - Octave version of modulator that outputs a raw file. + The modulator is driven by a test frame of bits. This + can then be played over a real channel or through a + channel simulator like PathSim. The sample rate can be + changed using "sox" to simulate differences in tx/rx + sample clocks. + + To generate 10 seconds of modulated signal: + + octave:8> fdmdv_mod("test.raw",1400*10); + +fdmdv_demod.m - Demodulator program that takes a raw file as input, + and works out the bit error rate using the known test + frame. Can be used to test the demod performs with + off-air signals, or signals that have been passed + through a channel simulator. + + To demodulate 2 seconds of the test.raw file generated + above: + + octave:9> fdmdv_demod("test.raw",1400*2); + 2464 bits 0 errors BER: 0.0000 + + It also produces several plots showing the internal + states of the demod. Useful for debugging and + observing what happens with various channels. + +fdmdv_demod_c.m - Takes an output text file from the C demod + fdmdv_demod.c and produces plots and measures BER. + Useful for evaluating fdmdv_demod.c performance. + The plots produced are identical to the Octave + version fdmdv_demod.m, allowing direct comparison of + the C and Octave versions. + +tfdmdv.m - Automatic tests that compare the Octave and C versions of + the FDMDV modem functions. First run unittest/tfdmdv, this + will generate a text file with test vectors from the C + version. Then run the Octave script tfdmdv and it will + generate Octave versions of the test vectors and compare + each vector with the C equivalent. Its plots the vectors + and and errors (green). Its also produces an automatic + check list based on test results. If the Octave or C modem + code is changed, this script should be used to ensure the + C and Octave versions remain identical. + +Modelling sample clock errors using sox +--------------------------------------- + +This introduces a simulated 1000ppm error: + + sox -r 8000 -s -2 mod_dqpsk.raw -s -2 mod_dqpsk_8008hz.raw rate -h 8008 + +TODO +---- + +[ ] implement ppm measurements in fdmdv_get_demod_stats() +[ ] try interfering sine wave + + maybe swept + + does modem fall over? +[ ] try non-flat channel, e.g. 3dB difference between hi and low tones + + make sure all estimators keep working +[ ] test rx level sensitivity, i.e. 0 to 20dB attenuation +[ ] make fine freq indep of amplitude + + use angle rather than imag coord +[ ] document use of fdmdv_ut and fdmdv_demod + PathSim +[ ] more positive form of sync reqd for DV frames? + + like using coarse_fine==1 to decode valid DV frame bit? + + when should we start decoding? +[ ] more robust track/acquite state machine? + + e.g. hang on thru the fades? +[ ] PAPR idea + + automatically tweak phases to reduce PAPR, e.g. slow variations in freq... +[ ] why is pilot noise_est twice as big as other carriers diff --git a/codec2/branches/0.7/README_fsk.txt b/codec2/branches/0.7/README_fsk.txt new file mode 100644 index 00000000..4638566f --- /dev/null +++ b/codec2/branches/0.7/README_fsk.txt @@ -0,0 +1,82 @@ + +README_fsk.txt +David Rowe +Created Jan 2016 + +A FSK modem with a non-coherent demodulator. Performance is within a +fraction of a dB of ideal. The demodulator automagically estimates +the tone frequencies and tracks frequency drift. + +Credits +------- + +The Octave version of the modem was developed by David Rowe. Brady +O'Brien ported the modem to C, and wrote the C/Octave tests. + +Quickstart +---------- + +Built as part of codec2-dev, see README for build instructions. + +1. Using 1000 test bits, generate 2FSK using a 8000 Hz sample rate, at + 100 symbols/s (== 100 bit/s for 2FSK), with two frequencies of 1200 + and 2400 Hz, and stream via stdout to "play" out speaker: + + $ cd build_linux/src + $ ./fsk_get_test_bits - 1000 | ./fsk_mod 2 8000 100 1200 1200 - - | play -t raw -r 8000 -s -2 - + + The low tone frequency is 1200Hz, and the upper tone 1200 + 1200 = 2400Hz. + +2. Measure the bit error rate over 10,000 bits of 100 bit/s 2FSK: + + $ ./fsk_get_test_bits - 10000 | ./fsk_mod 2 8000 100 1200 100 - - | ./fsk_demod -l 2 8000 100 - - | ./fsk_put_test_bits - + FSK BER 0.000000, bits tested 9800, bit errors 0 + + In this example the two tones are at 1200 and 1200+100 = 1300Hz. + A shift of 100Hz is the minimum possible for an incoherent FSK + demodulator that is running at 100 symbols/s. Note that -l or --lbr + initalizes the demodulator in 'low bit rate' mode. In low bit rate + mode, incoming samples are processed in 1 second chunks, giving a + very wide window for frequency and timing estimaton. Low speed mode + is well suited to applications that can tolerate long latency, such + as balloon telemetry. + + The demod and test frame logic takes a few frames to sync up, so + although we sent 10,000 bits, only 9800 are received. However + there were no errors in those received bits. + +3. Measure the bit error rate of 5000 bits at 1200 bits/s, using a + sample rate of 9600 Hz: + + $ ./fsk_get_test_bits - 5000 | ./fsk_mod 2 9600 1200 1200 1200 - - | ./fsk_demod -p 8 2 9600 1200 - - | ./fsk_put_test_bits - + FSK BER 0.000000, bits tested 4900, bit errors 0 + + In this example, the -l and --lbr options are left out setting the modem + up in "high speed" mode. In this mode, the demodulator operates on blocks of + 24 symbols at a time. In modes with a higher bitrate, this allows the modem + to operate with a much lower bit rate. High speed mode is well suited to + applications without much tolerance for latency or with limited processing + power and memory, such as PTT digital voice. + + In this example, the -p (or --conv) option is used. This specifies the + downconverted symbol size. The symbol period (Ts) must be divisible by + the supplied P parameter. In this case, Fs is 9600 and Rs is 1200, so Ts + is Fs/Rs, which is 8. In this case, 8 is the maximum P value allowed, + though 4 and 2 would also work. If P is not divisible by Ts, a failed + assert will fire and fsk_demod will exit. If -p is not supplied, it + will default to match Ts. In general, lower values of P result in less + memory use and CPU time spend, but may result in worse modem preformance. + P should be left alone unless CPU and memory usage needs to be lowered + for the application. + + (TODO, make this easier to understand, perhaps with figure) + +4. (TODO High bit rate example like 115k project Horus) + +5. Automatically check C implementation against Octave using a variety of test conditions and + channel impairments. + + $ cd octave + $ octave + octave:1> tfsk + diff --git a/codec2/branches/0.7/cmake/GetDependencies.cmake.in b/codec2/branches/0.7/cmake/GetDependencies.cmake.in new file mode 100644 index 00000000..0d25f670 --- /dev/null +++ b/codec2/branches/0.7/cmake/GetDependencies.cmake.in @@ -0,0 +1,24 @@ +# As this script is run in a new cmake instance, it does not have access to +# the existing cache variables. Pass them in via the configure_file command. +set(CMAKE_BINARY_DIR @CMAKE_BINARY_DIR@) +set(CMAKE_SOURCE_DIR @CMAKE_SOURCE_DIR@) +set(UNIX @UNIX@) +set(WIN32 @WIN32@) +set(CMAKE_CROSSCOMPILING @CMAKE_CROSSCOMPILING@) +set(CMAKE_FIND_LIBRARY_SUFFIXES @CMAKE_FIND_LIBRARY_SUFFIXES@) +set(CMAKE_FIND_LIBRARY_PREFIXES @CMAKE_FIND_LIBRARY_PREFIXES@) +set(CMAKE_SYSTEM_LIBRARY_PATH @CMAKE_SYSTEM_LIBRARY_PATH@) +set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@) +set(CODEC2_DLL ${CMAKE_BINARY_DIR}/src/libcodec2.dll) + +include(${CMAKE_SOURCE_DIR}/cmake/GetPrerequisites.cmake) +get_prerequisites(${CODEC2_DLL} _deps 1 0 "" "") +foreach(_runtime ${_deps}) + message("Looking for ${_runtime}") + find_library(RUNTIME_${_runtime} ${_runtime}) + message("${RUNTIME_${_runtime}}") + if(RUNTIME_${_runtime}) + file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" + TYPE EXECUTABLE FILES "${RUNTIME_${_runtime}}") + endif() +endforeach() diff --git a/codec2/branches/0.7/cmake/config.h.in b/codec2/branches/0.7/cmake/config.h.in new file mode 100644 index 00000000..60ee7d62 --- /dev/null +++ b/codec2/branches/0.7/cmake/config.h.in @@ -0,0 +1,23 @@ +/*-------------------------------------------------------------------------- + ** This file is autogenerated from config.h.in + ** during the cmake configuration of your project. If you need to make changes + ** edit the original file NOT THIS FILE. + ** --------------------------------------------------------------------------*/ +#ifndef _CONFIGURATION_HEADER_GUARD_H_ +#define _CONFIGURATION_HEADER_GUARD_H_ + +#define SIZEOF_INT @SIZEOF_INT@ +#cmakedefine HAVE_STDLIB_H @HAVE_STDLIB_H@ +#cmakedefine HAVE_STRING_H @HAVE_STRING_H@ +#cmakedefine HAVE_FLOOR @HAVE_FLOOR@ +#cmakedefine HAVE_CEIL @HAVE_CEIL@ +#cmakedefine HAVE_MEMSET @HAVE_MEMSET@ +#cmakedefine HAVE_POW @HAVE_POW@ +#cmakedefine HAVE_SQRT @HAVE_SQRT@ +#cmakedefine HAVE_SIN @HAVE_SIN@ +#cmakedefine HAVE_COS @HAVE_COS@ +#cmakedefine HAVE_ATAN2 @HAVE_ATAN2@ +#cmakedefine HAVE_LOG10 @HAVE_LOG10@ +#cmakedefine HAVE_ROUND @HAVE_ROUND@ +#cmakedefine HAVE_GETOPT @HAVE_GETOPT@ +#endif diff --git a/codec2/branches/0.7/codec2.pc.in b/codec2/branches/0.7/codec2.pc.in new file mode 100644 index 00000000..deb9dd0c --- /dev/null +++ b/codec2/branches/0.7/codec2.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@/ + +Name: codec2 +Description: A speech codec for 2400 bit/s and below +Requires: +Version: @CODEC2_VERSION@ +Libs: -L${libdir} -lcodec2 +Cflags: -I${includedir} diff --git a/codec2/branches/0.7/debian/changelog b/codec2/branches/0.7/debian/changelog new file mode 100644 index 00000000..214efcf9 --- /dev/null +++ b/codec2/branches/0.7/debian/changelog @@ -0,0 +1,5 @@ +codec2 (0.4-150830) unstable; urgency=low + + * Subversion snapshot of tag 0.4. + + -- Stuart Longland Sun, 30 Aug 2015 08:57:09 +1000 diff --git a/codec2/branches/0.7/debian/codec2.doc-base.EX b/codec2/branches/0.7/debian/codec2.doc-base.EX new file mode 100644 index 00000000..58360877 --- /dev/null +++ b/codec2/branches/0.7/debian/codec2.doc-base.EX @@ -0,0 +1,20 @@ +Document: codec2 +Title: Debian codec2 Manual +Author: +Abstract: This manual describes what codec2 is + and how it can be used to + manage online manuals on Debian systems. +Section: unknown + +Format: debiandoc-sgml +Files: /usr/share/doc/codec2/codec2.sgml.gz + +Format: postscript +Files: /usr/share/doc/codec2/codec2.ps.gz + +Format: text +Files: /usr/share/doc/codec2/codec2.text.gz + +Format: HTML +Index: /usr/share/doc/codec2/html/index.html +Files: /usr/share/doc/codec2/html/*.html diff --git a/codec2/branches/0.7/debian/codec2.install b/codec2/branches/0.7/debian/codec2.install new file mode 100644 index 00000000..1df36c61 --- /dev/null +++ b/codec2/branches/0.7/debian/codec2.install @@ -0,0 +1 @@ +usr/bin/* diff --git a/codec2/branches/0.7/debian/codec21.dirs b/codec2/branches/0.7/debian/codec21.dirs new file mode 100644 index 00000000..68457717 --- /dev/null +++ b/codec2/branches/0.7/debian/codec21.dirs @@ -0,0 +1 @@ +usr/lib diff --git a/codec2/branches/0.7/debian/codec21.install b/codec2/branches/0.7/debian/codec21.install new file mode 100644 index 00000000..d0dbfd18 --- /dev/null +++ b/codec2/branches/0.7/debian/codec21.install @@ -0,0 +1 @@ +usr/lib/lib*.so.* diff --git a/codec2/branches/0.7/debian/compat b/codec2/branches/0.7/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/codec2/branches/0.7/debian/compat @@ -0,0 +1 @@ +9 diff --git a/codec2/branches/0.7/debian/control b/codec2/branches/0.7/debian/control new file mode 100644 index 00000000..de9aa3bf --- /dev/null +++ b/codec2/branches/0.7/debian/control @@ -0,0 +1,36 @@ +Source: codec2 +Priority: optional +Maintainer: Stuart Longland +Build-Depends: debhelper (>= 9), cmake, libspeexdsp-dev +Standards-Version: 3.9.5 +Section: libs +Homepage: http://www.freedv.org + +Package: libcodec2-dev +Section: libdevel +Architecture: any +Depends: libcodec2 (= ${binary:Version}), ${misc:Depends} +Description: Codec 2: ultra-low bitrate voice codec. Headers. + Codec 2 is an ultra-low bitrate (sub 4kbps) voice codec + for use in radio frequency communications applications. + . + This package provides the headers. + +Package: libcodec2 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, libspeexdsp1 +Description: Codec 2: ultra-low bitrate voice codec. Library. + Codec 2 is an ultra-low bitrate (sub 4kbps) voice codec + for use in radio frequency communications applications. + . + This package provides the runtime library. + +Package: codec2 +Architecture: any +Depends: libcodec2 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Codec 2: ultra-low bitrate voice codec. Utilities. + Codec 2 is an ultra-low bitrate (sub 4kbps) voice codec + for use in radio frequency communications applications. + . + This package provides some command line utilities for encoding + and decoding codec2. diff --git a/codec2/branches/0.7/debian/copyright b/codec2/branches/0.7/debian/copyright new file mode 100644 index 00000000..598dd85a --- /dev/null +++ b/codec2/branches/0.7/debian/copyright @@ -0,0 +1,38 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: codec2 +Source: + +Files: * +Copyright: + +License: + + + . + + +# If you want to use GPL v2 or later for the /debian/* files use +# the following clauses, or change it to suit. Delete these two lines +Files: debian/* +Copyright: 2015 unknown +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". + +# Please also look if there are files or directories which have a +# different copyright/license attached and list them here. +# Please avoid to pick license terms that are more restrictive than the +# packaged work, as it may make Debian's contributions unacceptable upstream. diff --git a/codec2/branches/0.7/debian/docs b/codec2/branches/0.7/debian/docs new file mode 100644 index 00000000..8e229a37 --- /dev/null +++ b/codec2/branches/0.7/debian/docs @@ -0,0 +1,6 @@ +NEWS +README +README_fdmdv.txt +AUTHORS +ChangeLog +INSTALL diff --git a/codec2/branches/0.7/debian/libcodec2-dev.dirs b/codec2/branches/0.7/debian/libcodec2-dev.dirs new file mode 100644 index 00000000..44188162 --- /dev/null +++ b/codec2/branches/0.7/debian/libcodec2-dev.dirs @@ -0,0 +1,2 @@ +usr/lib +usr/include diff --git a/codec2/branches/0.7/debian/libcodec2-dev.install b/codec2/branches/0.7/debian/libcodec2-dev.install new file mode 100644 index 00000000..41a14144 --- /dev/null +++ b/codec2/branches/0.7/debian/libcodec2-dev.install @@ -0,0 +1 @@ +usr/include/* diff --git a/codec2/branches/0.7/debian/libcodec2.install b/codec2/branches/0.7/debian/libcodec2.install new file mode 100644 index 00000000..f1d0181f --- /dev/null +++ b/codec2/branches/0.7/debian/libcodec2.install @@ -0,0 +1 @@ +usr/lib/* diff --git a/codec2/branches/0.7/debian/rules b/codec2/branches/0.7/debian/rules new file mode 100755 index 00000000..c6cdbe71 --- /dev/null +++ b/codec2/branches/0.7/debian/rules @@ -0,0 +1,24 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#DH_VERBOSE = 1 + +# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/default.mk + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +# main packaging script based on dh7 syntax +%: + dh $@ --buildsystem=cmake + + diff --git a/codec2/branches/0.7/debian/source/format b/codec2/branches/0.7/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/codec2/branches/0.7/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/codec2/branches/0.7/octave/2400ab_frame_design.ods b/codec2/branches/0.7/octave/2400ab_frame_design.ods new file mode 100644 index 0000000000000000000000000000000000000000..015fc6bbe10b4e0cc9402612efbf333c3ba8703f GIT binary patch literal 19194 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 IC~*Vv07ex|%m4rY literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/octave/H2064_516_sparse.mat b/codec2/branches/0.7/octave/H2064_516_sparse.mat new file mode 100644 index 00000000..e684c2e6 --- /dev/null +++ b/codec2/branches/0.7/octave/H2064_516_sparse.mat @@ -0,0 +1,7231 @@ +# Created by Octave 3.8.1, Wed Mar 23 13:59:47 2016 ACDT +# name: HRA +# type: sparse matrix +# nnz: 7223 +# rows: 516 +# columns: 2580 +208 1 1 +296 1 1 +368 1 1 +242 2 1 +323 2 1 +362 2 1 +84 3 1 +150 3 1 +437 3 1 +114 4 1 +211 4 1 +409 4 1 +314 5 1 +361 5 1 +372 5 1 +135 6 1 +261 6 1 +270 6 1 +349 7 1 +422 7 1 +481 7 1 +90 8 1 +167 8 1 +300 8 1 +64 9 1 +212 9 1 +407 9 1 +57 10 1 +195 10 1 +253 10 1 +26 11 1 +50 11 1 +55 11 1 +52 12 1 +317 12 1 +488 12 1 +16 13 1 +406 13 1 +487 13 1 +142 14 1 +372 14 1 +470 14 1 +120 15 1 +360 15 1 +429 15 1 +244 16 1 +314 16 1 +431 16 1 +167 17 1 +399 17 1 +402 17 1 +164 18 1 +203 18 1 +259 18 1 +133 19 1 +136 19 1 +404 19 1 +179 20 1 +211 20 1 +257 20 1 +22 21 1 +56 21 1 +101 21 1 +180 22 1 +195 22 1 +243 22 1 +413 23 1 +436 23 1 +463 23 1 +161 24 1 +229 24 1 +487 24 1 +224 25 1 +489 25 1 +514 25 1 +121 26 1 +295 26 1 +496 26 1 +57 27 1 +101 27 1 +150 27 1 +22 28 1 +109 28 1 +358 28 1 +394 29 1 +487 29 1 +504 29 1 +17 30 1 +184 30 1 +234 30 1 +9 31 1 +87 31 1 +490 31 1 +54 32 1 +279 32 1 +511 32 1 +84 33 1 +233 33 1 +240 33 1 +20 34 1 +399 34 1 +415 34 1 +98 35 1 +176 35 1 +412 35 1 +311 36 1 +470 36 1 +484 36 1 +322 37 1 +433 37 1 +490 37 1 +308 38 1 +364 38 1 +416 38 1 +86 39 1 +197 39 1 +252 39 1 +91 40 1 +115 40 1 +472 40 1 +77 41 1 +194 41 1 +489 41 1 +41 42 1 +314 42 1 +478 42 1 +110 43 1 +423 43 1 +493 43 1 +192 44 1 +246 44 1 +381 44 1 +18 45 1 +98 45 1 +139 45 1 +11 46 1 +401 46 1 +480 46 1 +210 47 1 +291 47 1 +511 47 1 +133 48 1 +268 48 1 +362 48 1 +248 49 1 +272 49 1 +293 49 1 +276 50 1 +357 50 1 +466 50 1 +389 51 1 +458 51 1 +503 51 1 +100 52 1 +298 52 1 +359 52 1 +37 53 1 +327 53 1 +342 53 1 +4 54 1 +21 54 1 +142 54 1 +239 55 1 +298 55 1 +326 55 1 +15 56 1 +299 56 1 +369 56 1 +32 57 1 +225 57 1 +304 57 1 +15 58 1 +220 58 1 +320 58 1 +7 59 1 +272 59 1 +364 59 1 +10 60 1 +51 60 1 +486 60 1 +109 61 1 +177 61 1 +261 61 1 +82 62 1 +93 62 1 +105 62 1 +19 63 1 +84 63 1 +316 63 1 +50 64 1 +403 64 1 +471 64 1 +137 65 1 +150 65 1 +476 65 1 +278 66 1 +336 66 1 +430 66 1 +43 67 1 +275 67 1 +460 67 1 +181 68 1 +236 68 1 +379 68 1 +89 69 1 +476 69 1 +484 69 1 +206 70 1 +243 70 1 +253 70 1 +113 71 1 +261 71 1 +446 71 1 +285 72 1 +373 72 1 +400 72 1 +10 73 1 +330 73 1 +447 73 1 +95 74 1 +248 74 1 +373 74 1 +12 75 1 +310 75 1 +472 75 1 +180 76 1 +365 76 1 +490 76 1 +23 77 1 +155 77 1 +272 77 1 +93 78 1 +240 78 1 +401 78 1 +100 79 1 +144 79 1 +158 79 1 +124 80 1 +276 80 1 +471 80 1 +200 81 1 +229 81 1 +328 81 1 +130 82 1 +292 82 1 +417 82 1 +81 83 1 +99 83 1 +312 83 1 +149 84 1 +175 84 1 +344 84 1 +6 85 1 +101 85 1 +331 85 1 +251 86 1 +317 86 1 +429 86 1 +181 87 1 +365 87 1 +383 87 1 +227 88 1 +297 88 1 +341 88 1 +156 89 1 +404 89 1 +501 89 1 +215 90 1 +260 90 1 +361 90 1 +194 91 1 +333 91 1 +410 91 1 +284 92 1 +417 92 1 +480 92 1 +206 93 1 +462 93 1 +477 93 1 +177 94 1 +434 94 1 +492 94 1 +171 95 1 +474 95 1 +508 95 1 +174 96 1 +444 96 1 +482 96 1 +40 97 1 +119 97 1 +332 97 1 +136 98 1 +309 98 1 +336 98 1 +187 99 1 +261 99 1 +429 99 1 +89 100 1 +260 100 1 +310 100 1 +98 101 1 +344 101 1 +369 101 1 +156 102 1 +435 102 1 +460 102 1 +44 103 1 +80 103 1 +291 103 1 +30 104 1 +123 104 1 +346 104 1 +48 105 1 +257 105 1 +365 105 1 +78 106 1 +183 106 1 +392 106 1 +349 107 1 +358 107 1 +402 107 1 +126 108 1 +197 108 1 +452 108 1 +56 109 1 +78 109 1 +120 109 1 +3 110 1 +16 110 1 +430 110 1 +212 111 1 +264 111 1 +301 111 1 +43 112 1 +260 112 1 +419 112 1 +111 113 1 +459 113 1 +462 113 1 +183 114 1 +195 114 1 +406 114 1 +63 115 1 +390 115 1 +410 115 1 +54 116 1 +147 116 1 +342 116 1 +35 117 1 +217 117 1 +493 117 1 +63 118 1 +467 118 1 +500 118 1 +333 119 1 +353 119 1 +390 119 1 +158 120 1 +165 120 1 +498 120 1 +96 121 1 +120 121 1 +378 121 1 +100 122 1 +151 122 1 +230 122 1 +270 123 1 +335 123 1 +403 123 1 +38 124 1 +83 124 1 +188 124 1 +97 125 1 +106 125 1 +443 125 1 +4 126 1 +28 126 1 +258 126 1 +139 127 1 +326 127 1 +505 127 1 +163 128 1 +252 128 1 +499 128 1 +67 129 1 +70 129 1 +148 129 1 +251 130 1 +298 130 1 +508 130 1 +139 131 1 +182 131 1 +485 131 1 +42 132 1 +153 132 1 +241 132 1 +214 133 1 +300 133 1 +382 133 1 +117 134 1 +260 134 1 +289 134 1 +26 135 1 +122 135 1 +264 135 1 +98 136 1 +111 136 1 +182 136 1 +132 137 1 +143 137 1 +455 137 1 +105 138 1 +302 138 1 +481 138 1 +13 139 1 +135 139 1 +264 139 1 +61 140 1 +235 140 1 +451 140 1 +330 141 1 +362 141 1 +489 141 1 +223 142 1 +236 142 1 +483 142 1 +183 143 1 +232 143 1 +485 143 1 +95 144 1 +287 144 1 +365 144 1 +295 145 1 +371 145 1 +376 145 1 +95 146 1 +309 146 1 +447 146 1 +55 147 1 +248 147 1 +301 147 1 +29 148 1 +248 148 1 +382 148 1 +65 149 1 +176 149 1 +278 149 1 +35 150 1 +215 150 1 +237 150 1 +75 151 1 +169 151 1 +409 151 1 +130 152 1 +183 152 1 +285 152 1 +8 153 1 +155 153 1 +168 153 1 +98 154 1 +140 154 1 +292 154 1 +344 155 1 +446 155 1 +463 155 1 +46 156 1 +91 156 1 +290 156 1 +239 157 1 +277 157 1 +482 157 1 +155 158 1 +263 158 1 +339 158 1 +131 159 1 +234 159 1 +323 159 1 +75 160 1 +126 160 1 +376 160 1 +246 161 1 +376 161 1 +386 161 1 +3 162 1 +335 162 1 +495 162 1 +44 163 1 +162 163 1 +286 163 1 +260 164 1 +490 164 1 +502 164 1 +199 165 1 +398 165 1 +450 165 1 +21 166 1 +182 166 1 +322 166 1 +99 167 1 +105 167 1 +115 167 1 +118 168 1 +378 168 1 +390 168 1 +76 169 1 +469 169 1 +483 169 1 +8 170 1 +159 170 1 +370 170 1 +87 171 1 +119 171 1 +426 171 1 +271 172 1 +457 172 1 +461 172 1 +257 173 1 +292 173 1 +441 173 1 +171 174 1 +249 174 1 +406 174 1 +98 175 1 +108 175 1 +162 175 1 +44 176 1 +59 176 1 +73 176 1 +255 177 1 +451 177 1 +506 177 1 +17 178 1 +20 178 1 +256 178 1 +276 179 1 +362 179 1 +511 179 1 +91 180 1 +228 180 1 +507 180 1 +50 181 1 +57 181 1 +107 181 1 +21 182 1 +306 182 1 +498 182 1 +90 183 1 +459 183 1 +491 183 1 +262 184 1 +301 184 1 +323 184 1 +118 185 1 +208 185 1 +274 185 1 +208 186 1 +329 186 1 +478 186 1 +214 187 1 +357 187 1 +516 187 1 +35 188 1 +82 188 1 +337 188 1 +140 189 1 +396 189 1 +450 189 1 +159 190 1 +279 190 1 +304 190 1 +58 191 1 +137 191 1 +183 191 1 +277 192 1 +396 192 1 +502 192 1 +158 193 1 +272 193 1 +285 193 1 +180 194 1 +202 194 1 +249 194 1 +53 195 1 +396 195 1 +420 195 1 +93 196 1 +282 196 1 +427 196 1 +58 197 1 +120 197 1 +349 197 1 +264 198 1 +308 198 1 +386 198 1 +40 199 1 +389 199 1 +508 199 1 +98 200 1 +287 200 1 +353 200 1 +4 201 1 +43 201 1 +413 201 1 +284 202 1 +311 202 1 +500 202 1 +183 203 1 +371 203 1 +375 203 1 +24 204 1 +59 204 1 +304 204 1 +7 205 1 +326 205 1 +485 205 1 +123 206 1 +125 206 1 +410 206 1 +133 207 1 +223 207 1 +484 207 1 +57 208 1 +190 208 1 +306 208 1 +223 209 1 +285 209 1 +353 209 1 +124 210 1 +134 210 1 +431 210 1 +156 211 1 +348 211 1 +377 211 1 +202 212 1 +219 212 1 +239 212 1 +34 213 1 +74 213 1 +156 213 1 +324 214 1 +343 214 1 +438 214 1 +67 215 1 +72 215 1 +402 215 1 +452 216 1 +455 216 1 +499 216 1 +63 217 1 +367 217 1 +503 217 1 +123 218 1 +179 218 1 +200 218 1 +303 219 1 +368 219 1 +458 219 1 +303 220 1 +395 220 1 +419 220 1 +169 221 1 +267 221 1 +490 221 1 +40 222 1 +227 222 1 +230 222 1 +32 223 1 +59 223 1 +203 223 1 +24 224 1 +225 224 1 +397 224 1 +32 225 1 +65 225 1 +73 225 1 +5 226 1 +21 226 1 +436 226 1 +220 227 1 +300 227 1 +398 227 1 +218 228 1 +310 228 1 +326 228 1 +103 229 1 +266 229 1 +293 229 1 +222 230 1 +259 230 1 +363 230 1 +113 231 1 +362 231 1 +416 231 1 +111 232 1 +168 232 1 +497 232 1 +100 233 1 +104 233 1 +458 233 1 +30 234 1 +69 234 1 +250 234 1 +146 235 1 +344 235 1 +443 235 1 +266 236 1 +417 236 1 +460 236 1 +4 237 1 +47 237 1 +60 237 1 +195 238 1 +335 238 1 +476 238 1 +14 239 1 +103 239 1 +227 239 1 +55 240 1 +126 240 1 +392 240 1 +145 241 1 +394 241 1 +494 241 1 +37 242 1 +41 242 1 +352 242 1 +40 243 1 +122 243 1 +422 243 1 +18 244 1 +166 244 1 +383 244 1 +184 245 1 +313 245 1 +468 245 1 +188 246 1 +265 246 1 +344 246 1 +267 247 1 +438 247 1 +443 247 1 +38 248 1 +118 248 1 +199 248 1 +116 249 1 +265 249 1 +425 249 1 +35 250 1 +204 250 1 +417 250 1 +60 251 1 +316 251 1 +496 251 1 +53 252 1 +439 252 1 +452 252 1 +133 253 1 +142 253 1 +472 253 1 +58 254 1 +90 254 1 +396 254 1 +9 255 1 +180 255 1 +246 255 1 +296 256 1 +440 256 1 +449 256 1 +63 257 1 +281 257 1 +458 257 1 +57 258 1 +392 258 1 +395 258 1 +30 259 1 +312 259 1 +398 259 1 +17 260 1 +210 260 1 +283 260 1 +86 261 1 +137 261 1 +253 261 1 +157 262 1 +189 262 1 +391 262 1 +105 263 1 +240 263 1 +307 263 1 +29 264 1 +247 264 1 +268 264 1 +73 265 1 +240 265 1 +337 265 1 +285 266 1 +320 266 1 +501 266 1 +122 267 1 +251 267 1 +269 267 1 +9 268 1 +157 268 1 +499 268 1 +31 269 1 +324 269 1 +409 269 1 +199 270 1 +208 270 1 +408 270 1 +347 271 1 +415 271 1 +434 271 1 +73 272 1 +245 272 1 +365 272 1 +55 273 1 +180 273 1 +264 273 1 +135 274 1 +262 274 1 +407 274 1 +86 275 1 +94 275 1 +267 275 1 +2 276 1 +141 276 1 +150 276 1 +42 277 1 +191 277 1 +253 277 1 +67 278 1 +110 278 1 +254 278 1 +119 279 1 +165 279 1 +269 279 1 +21 280 1 +165 280 1 +185 280 1 +351 281 1 +361 281 1 +434 281 1 +35 282 1 +61 282 1 +306 282 1 +213 283 1 +488 283 1 +508 283 1 +173 284 1 +378 284 1 +510 284 1 +61 285 1 +138 285 1 +287 285 1 +176 286 1 +178 286 1 +347 286 1 +194 287 1 +229 287 1 +318 287 1 +109 288 1 +396 288 1 +439 288 1 +72 289 1 +157 289 1 +235 289 1 +77 290 1 +168 290 1 +307 290 1 +273 291 1 +397 291 1 +503 291 1 +133 292 1 +266 292 1 +281 292 1 +244 293 1 +289 293 1 +303 293 1 +90 294 1 +240 294 1 +468 294 1 +313 295 1 +347 295 1 +366 295 1 +220 296 1 +299 296 1 +415 296 1 +27 297 1 +84 297 1 +434 297 1 +192 298 1 +451 298 1 +480 298 1 +63 299 1 +133 299 1 +368 299 1 +299 300 1 +391 300 1 +497 300 1 +208 301 1 +469 301 1 +500 301 1 +202 302 1 +324 302 1 +504 302 1 +3 303 1 +137 303 1 +195 303 1 +66 304 1 +116 304 1 +188 304 1 +14 305 1 +60 305 1 +125 305 1 +19 306 1 +365 306 1 +502 306 1 +127 307 1 +207 307 1 +496 307 1 +68 308 1 +200 308 1 +475 308 1 +348 309 1 +472 309 1 +492 309 1 +246 310 1 +450 310 1 +481 310 1 +26 311 1 +428 311 1 +501 311 1 +87 312 1 +330 312 1 +407 312 1 +75 313 1 +139 313 1 +309 313 1 +20 314 1 +159 314 1 +302 314 1 +215 315 1 +223 315 1 +372 315 1 +93 316 1 +217 316 1 +442 316 1 +212 317 1 +330 317 1 +357 317 1 +180 318 1 +245 318 1 +464 318 1 +149 319 1 +234 319 1 +436 319 1 +114 320 1 +238 320 1 +249 320 1 +133 321 1 +418 321 1 +429 321 1 +48 322 1 +391 322 1 +493 322 1 +235 323 1 +367 323 1 +412 323 1 +17 324 1 +308 324 1 +340 324 1 +247 325 1 +291 325 1 +385 325 1 +257 326 1 +304 326 1 +489 326 1 +42 327 1 +67 327 1 +172 327 1 +149 328 1 +244 328 1 +353 328 1 +57 329 1 +288 329 1 +322 329 1 +363 330 1 +382 330 1 +477 330 1 +75 331 1 +130 331 1 +439 331 1 +334 332 1 +461 332 1 +509 332 1 +67 333 1 +335 333 1 +490 333 1 +97 334 1 +118 334 1 +311 334 1 +29 335 1 +187 335 1 +478 335 1 +109 336 1 +334 336 1 +364 336 1 +241 337 1 +324 337 1 +450 337 1 +59 338 1 +441 338 1 +448 338 1 +332 339 1 +462 339 1 +479 339 1 +15 340 1 +112 340 1 +372 340 1 +228 341 1 +445 341 1 +463 341 1 +6 342 1 +59 342 1 +495 342 1 +186 343 1 +214 343 1 +312 343 1 +81 344 1 +230 344 1 +269 344 1 +271 345 1 +372 345 1 +425 345 1 +31 346 1 +44 346 1 +341 346 1 +103 347 1 +106 347 1 +501 347 1 +122 348 1 +167 348 1 +415 348 1 +150 349 1 +181 349 1 +193 349 1 +105 350 1 +211 350 1 +225 350 1 +110 351 1 +193 351 1 +481 351 1 +92 352 1 +148 352 1 +437 352 1 +277 353 1 +409 353 1 +433 353 1 +213 354 1 +264 354 1 +281 354 1 +358 355 1 +364 355 1 +509 355 1 +37 356 1 +353 356 1 +428 356 1 +100 357 1 +174 357 1 +278 357 1 +129 358 1 +263 358 1 +509 358 1 +46 359 1 +283 359 1 +458 359 1 +367 360 1 +406 360 1 +506 360 1 +118 361 1 +312 361 1 +481 361 1 +26 362 1 +349 362 1 +509 362 1 +115 363 1 +118 363 1 +463 363 1 +211 364 1 +455 364 1 +504 364 1 +3 365 1 +181 365 1 +209 365 1 +77 366 1 +259 366 1 +415 366 1 +217 367 1 +323 367 1 +510 367 1 +23 368 1 +175 368 1 +347 368 1 +24 369 1 +33 369 1 +246 369 1 +145 370 1 +152 370 1 +388 370 1 +70 371 1 +299 371 1 +307 371 1 +48 372 1 +141 372 1 +237 372 1 +68 373 1 +320 373 1 +472 373 1 +179 374 1 +314 374 1 +407 374 1 +112 375 1 +131 375 1 +318 375 1 +30 376 1 +62 376 1 +228 376 1 +110 377 1 +235 377 1 +441 377 1 +177 378 1 +335 378 1 +417 378 1 +14 379 1 +231 379 1 +467 379 1 +97 380 1 +340 380 1 +469 380 1 +68 381 1 +244 381 1 +457 381 1 +66 382 1 +425 382 1 +515 382 1 +103 383 1 +169 383 1 +324 383 1 +105 384 1 +311 384 1 +402 384 1 +83 385 1 +497 385 1 +510 385 1 +231 386 1 +241 386 1 +254 386 1 +29 387 1 +37 387 1 +112 387 1 +383 388 1 +436 388 1 +470 388 1 +45 389 1 +117 389 1 +345 389 1 +64 390 1 +184 390 1 +463 390 1 +42 391 1 +294 391 1 +302 391 1 +32 392 1 +157 392 1 +378 392 1 +201 393 1 +350 393 1 +416 393 1 +269 394 1 +301 394 1 +312 394 1 +67 395 1 +94 395 1 +241 395 1 +9 396 1 +162 396 1 +381 396 1 +149 397 1 +273 397 1 +327 397 1 +3 398 1 +13 398 1 +94 398 1 +34 399 1 +182 399 1 +207 399 1 +86 400 1 +101 400 1 +335 400 1 +373 401 1 +486 401 1 +498 401 1 +51 402 1 +341 402 1 +343 402 1 +409 403 1 +434 403 1 +476 403 1 +130 404 1 +322 404 1 +427 404 1 +39 405 1 +74 405 1 +444 405 1 +80 406 1 +144 406 1 +351 406 1 +177 407 1 +284 407 1 +414 407 1 +118 408 1 +139 408 1 +186 408 1 +34 409 1 +111 409 1 +178 409 1 +248 410 1 +403 410 1 +457 410 1 +175 411 1 +214 411 1 +459 411 1 +50 412 1 +52 412 1 +460 412 1 +37 413 1 +323 413 1 +333 413 1 +76 414 1 +327 414 1 +471 414 1 +14 415 1 +172 415 1 +334 415 1 +7 416 1 +227 416 1 +389 416 1 +122 417 1 +230 417 1 +398 417 1 +49 418 1 +208 418 1 +327 418 1 +262 419 1 +277 419 1 +315 419 1 +27 420 1 +221 420 1 +504 420 1 +79 421 1 +120 421 1 +481 421 1 +102 422 1 +409 422 1 +437 422 1 +295 423 1 +339 423 1 +386 423 1 +113 424 1 +123 424 1 +431 424 1 +26 425 1 +223 425 1 +488 425 1 +111 426 1 +252 426 1 +442 426 1 +135 427 1 +209 427 1 +241 427 1 +10 428 1 +237 428 1 +356 428 1 +356 429 1 +429 429 1 +471 429 1 +97 430 1 +295 430 1 +402 430 1 +21 431 1 +253 431 1 +424 431 1 +2 432 1 +35 432 1 +433 432 1 +129 433 1 +162 433 1 +287 433 1 +451 434 1 +454 434 1 +459 434 1 +140 435 1 +243 435 1 +298 435 1 +60 436 1 +199 436 1 +463 436 1 +42 437 1 +295 437 1 +322 437 1 +191 438 1 +385 438 1 +458 438 1 +33 439 1 +360 439 1 +386 439 1 +152 440 1 +241 440 1 +464 440 1 +25 441 1 +170 441 1 +232 441 1 +279 442 1 +390 442 1 +492 442 1 +99 443 1 +175 443 1 +285 443 1 +22 444 1 +402 444 1 +441 444 1 +124 445 1 +198 445 1 +227 445 1 +168 446 1 +288 446 1 +292 446 1 +305 447 1 +397 447 1 +405 447 1 +34 448 1 +275 448 1 +377 448 1 +104 449 1 +330 449 1 +336 449 1 +224 450 1 +267 450 1 +466 450 1 +154 451 1 +161 451 1 +441 451 1 +50 452 1 +341 452 1 +513 452 1 +71 453 1 +283 453 1 +350 453 1 +97 454 1 +193 454 1 +276 454 1 +60 455 1 +62 455 1 +142 455 1 +209 456 1 +258 456 1 +492 456 1 +73 457 1 +162 457 1 +176 457 1 +57 458 1 +254 458 1 +404 458 1 +10 459 1 +259 459 1 +286 459 1 +322 460 1 +374 460 1 +437 460 1 +159 461 1 +408 461 1 +483 461 1 +375 462 1 +415 462 1 +474 462 1 +104 463 1 +268 463 1 +446 463 1 +17 464 1 +54 464 1 +291 464 1 +273 465 1 +312 465 1 +323 465 1 +374 466 1 +424 466 1 +474 466 1 +81 467 1 +302 467 1 +463 467 1 +121 468 1 +342 468 1 +414 468 1 +160 469 1 +376 469 1 +496 469 1 +157 470 1 +172 470 1 +231 470 1 +411 471 1 +453 471 1 +493 471 1 +88 472 1 +214 472 1 +491 472 1 +236 473 1 +281 473 1 +464 473 1 +166 474 1 +379 474 1 +484 474 1 +88 475 1 +447 475 1 +448 475 1 +53 476 1 +170 476 1 +191 476 1 +164 477 1 +434 477 1 +441 477 1 +135 478 1 +230 478 1 +258 478 1 +36 479 1 +121 479 1 +296 479 1 +375 480 1 +423 480 1 +497 480 1 +291 481 1 +305 481 1 +381 481 1 +211 482 1 +441 482 1 +484 482 1 +4 483 1 +276 483 1 +419 483 1 +233 484 1 +244 484 1 +318 484 1 +84 485 1 +121 485 1 +125 485 1 +94 486 1 +110 486 1 +222 486 1 +47 487 1 +461 487 1 +487 487 1 +29 488 1 +323 488 1 +516 488 1 +10 489 1 +151 489 1 +285 489 1 +306 490 1 +309 490 1 +502 490 1 +54 491 1 +431 491 1 +449 491 1 +183 492 1 +202 492 1 +294 492 1 +16 493 1 +200 493 1 +211 493 1 +128 494 1 +329 494 1 +384 494 1 +42 495 1 +210 495 1 +358 495 1 +86 496 1 +352 496 1 +451 496 1 +96 497 1 +164 497 1 +414 497 1 +488 498 1 +503 498 1 +509 498 1 +31 499 1 +113 499 1 +135 499 1 +109 500 1 +126 500 1 +241 500 1 +150 501 1 +231 501 1 +444 501 1 +42 502 1 +152 502 1 +392 502 1 +332 503 1 +454 503 1 +474 503 1 +110 504 1 +311 504 1 +469 504 1 +315 505 1 +433 505 1 +444 505 1 +44 506 1 +86 506 1 +203 506 1 +321 507 1 +449 507 1 +500 507 1 +82 508 1 +130 508 1 +282 508 1 +109 509 1 +231 509 1 +350 509 1 +235 510 1 +262 510 1 +286 510 1 +80 511 1 +189 511 1 +231 511 1 +212 512 1 +290 512 1 +478 512 1 +35 513 1 +288 513 1 +365 513 1 +128 514 1 +429 514 1 +465 514 1 +80 515 1 +143 515 1 +467 515 1 +215 516 1 +311 516 1 +472 516 1 +7 517 1 +70 517 1 +497 517 1 +115 518 1 +226 518 1 +484 518 1 +44 519 1 +451 519 1 +513 519 1 +102 520 1 +277 520 1 +513 520 1 +281 521 1 +362 521 1 +455 521 1 +86 522 1 +134 522 1 +242 522 1 +27 523 1 +51 523 1 +502 523 1 +79 524 1 +81 524 1 +385 524 1 +280 525 1 +343 525 1 +504 525 1 +33 526 1 +171 526 1 +358 526 1 +227 527 1 +466 527 1 +479 527 1 +142 528 1 +149 528 1 +390 528 1 +113 529 1 +194 529 1 +407 529 1 +104 530 1 +310 530 1 +416 530 1 +102 531 1 +119 531 1 +266 531 1 +281 532 1 +315 532 1 +330 532 1 +161 533 1 +186 533 1 +206 533 1 +238 534 1 +300 534 1 +412 534 1 +197 535 1 +469 535 1 +471 535 1 +106 536 1 +349 536 1 +496 536 1 +111 537 1 +427 537 1 +498 537 1 +72 538 1 +123 538 1 +380 538 1 +163 539 1 +168 539 1 +325 539 1 +76 540 1 +117 540 1 +159 540 1 +41 541 1 +174 541 1 +219 541 1 +58 542 1 +144 542 1 +504 542 1 +4 543 1 +224 543 1 +447 543 1 +46 544 1 +116 544 1 +340 544 1 +45 545 1 +173 545 1 +383 545 1 +122 546 1 +198 546 1 +416 546 1 +281 547 1 +457 547 1 +475 547 1 +219 548 1 +287 548 1 +373 548 1 +52 549 1 +147 549 1 +410 549 1 +53 550 1 +65 550 1 +486 550 1 +45 551 1 +258 551 1 +368 551 1 +66 552 1 +272 552 1 +501 552 1 +264 553 1 +499 553 1 +511 553 1 +69 554 1 +315 554 1 +413 554 1 +37 555 1 +81 555 1 +91 555 1 +16 556 1 +186 556 1 +278 556 1 +138 557 1 +168 557 1 +257 557 1 +221 558 1 +341 558 1 +486 558 1 +176 559 1 +316 559 1 +369 559 1 +176 560 1 +190 560 1 +506 560 1 +98 561 1 +178 561 1 +214 561 1 +42 562 1 +291 562 1 +402 562 1 +75 563 1 +232 563 1 +430 563 1 +92 564 1 +280 564 1 +348 564 1 +80 565 1 +174 565 1 +476 565 1 +158 566 1 +260 566 1 +333 566 1 +163 567 1 +242 567 1 +331 567 1 +71 568 1 +226 568 1 +441 568 1 +26 569 1 +181 569 1 +204 569 1 +49 570 1 +120 570 1 +187 570 1 +109 571 1 +113 571 1 +450 571 1 +108 572 1 +138 572 1 +194 572 1 +70 573 1 +294 573 1 +382 573 1 +85 574 1 +106 574 1 +224 574 1 +378 575 1 +481 575 1 +497 575 1 +186 576 1 +287 576 1 +411 576 1 +178 577 1 +377 577 1 +462 577 1 +9 578 1 +104 578 1 +252 578 1 +12 579 1 +125 579 1 +275 579 1 +4 580 1 +383 580 1 +457 580 1 +74 581 1 +234 581 1 +446 581 1 +25 582 1 +369 582 1 +415 582 1 +65 583 1 +289 583 1 +502 583 1 +207 584 1 +348 584 1 +413 584 1 +8 585 1 +52 585 1 +121 585 1 +339 586 1 +389 586 1 +515 586 1 +5 587 1 +239 587 1 +485 587 1 +45 588 1 +219 588 1 +476 588 1 +205 589 1 +344 589 1 +353 589 1 +163 590 1 +378 590 1 +381 590 1 +234 591 1 +338 591 1 +488 591 1 +14 592 1 +418 592 1 +480 592 1 +56 593 1 +137 593 1 +385 593 1 +77 594 1 +363 594 1 +425 594 1 +62 595 1 +116 595 1 +314 595 1 +185 596 1 +207 596 1 +224 596 1 +55 597 1 +335 597 1 +383 597 1 +89 598 1 +449 598 1 +506 598 1 +19 599 1 +202 599 1 +280 599 1 +228 600 1 +358 600 1 +515 600 1 +117 601 1 +216 601 1 +388 601 1 +113 602 1 +134 602 1 +422 602 1 +80 603 1 +319 603 1 +386 603 1 +9 604 1 +100 604 1 +396 604 1 +8 605 1 +11 605 1 +408 605 1 +38 606 1 +265 606 1 +329 606 1 +74 607 1 +233 607 1 +340 607 1 +10 608 1 +172 608 1 +371 608 1 +112 609 1 +267 609 1 +359 609 1 +32 610 1 +45 610 1 +138 610 1 +205 611 1 +256 611 1 +431 611 1 +8 612 1 +23 612 1 +200 612 1 +242 613 1 +318 613 1 +361 613 1 +142 614 1 +221 614 1 +393 614 1 +119 615 1 +169 615 1 +189 615 1 +26 616 1 +245 616 1 +436 616 1 +158 617 1 +306 617 1 +411 617 1 +28 618 1 +281 618 1 +319 618 1 +148 619 1 +181 619 1 +316 619 1 +54 620 1 +289 620 1 +478 620 1 +69 621 1 +116 621 1 +293 621 1 +28 622 1 +173 622 1 +390 622 1 +81 623 1 +346 623 1 +422 623 1 +91 624 1 +327 624 1 +414 624 1 +142 625 1 +194 625 1 +445 625 1 +78 626 1 +205 626 1 +232 626 1 +158 627 1 +326 627 1 +503 627 1 +49 628 1 +345 628 1 +397 628 1 +66 629 1 +201 629 1 +443 629 1 +45 630 1 +111 630 1 +296 630 1 +179 631 1 +448 631 1 +493 631 1 +249 632 1 +366 632 1 +374 632 1 +91 633 1 +399 633 1 +432 633 1 +90 634 1 +293 634 1 +430 634 1 +219 635 1 +222 635 1 +493 635 1 +153 636 1 +170 636 1 +206 636 1 +339 637 1 +358 637 1 +437 637 1 +90 638 1 +442 638 1 +477 638 1 +14 639 1 +19 639 1 +295 639 1 +56 640 1 +187 640 1 +352 640 1 +60 641 1 +159 641 1 +492 641 1 +392 642 1 +456 642 1 +509 642 1 +9 643 1 +299 643 1 +375 643 1 +162 644 1 +206 644 1 +214 644 1 +274 645 1 +290 645 1 +314 645 1 +102 646 1 +169 646 1 +430 646 1 +79 647 1 +253 647 1 +283 647 1 +89 648 1 +412 648 1 +467 648 1 +206 649 1 +252 649 1 +491 649 1 +114 650 1 +202 650 1 +350 650 1 +365 651 1 +377 651 1 +421 651 1 +2 652 1 +331 652 1 +499 652 1 +232 653 1 +497 653 1 +499 653 1 +172 654 1 +203 654 1 +511 654 1 +36 655 1 +313 655 1 +367 655 1 +8 656 1 +115 656 1 +125 656 1 +14 657 1 +255 657 1 +379 657 1 +317 658 1 +373 658 1 +482 658 1 +173 659 1 +364 659 1 +476 659 1 +65 660 1 +237 660 1 +505 660 1 +2 661 1 +245 661 1 +411 661 1 +37 662 1 +291 662 1 +446 662 1 +112 663 1 +269 663 1 +507 663 1 +273 664 1 +342 664 1 +390 664 1 +38 665 1 +54 665 1 +264 665 1 +179 666 1 +218 666 1 +290 666 1 +107 667 1 +269 667 1 +419 667 1 +244 668 1 +373 668 1 +460 668 1 +9 669 1 +170 669 1 +474 669 1 +173 670 1 +256 670 1 +414 670 1 +67 671 1 +270 671 1 +422 671 1 +141 672 1 +213 672 1 +317 672 1 +265 673 1 +305 673 1 +327 673 1 +156 674 1 +288 674 1 +437 674 1 +96 675 1 +203 675 1 +422 675 1 +102 676 1 +315 676 1 +404 676 1 +158 677 1 +238 677 1 +320 677 1 +77 678 1 +87 678 1 +416 678 1 +96 679 1 +192 679 1 +242 679 1 +331 680 1 +334 680 1 +362 680 1 +2 681 1 +26 681 1 +429 681 1 +102 682 1 +127 682 1 +366 682 1 +302 683 1 +352 683 1 +399 683 1 +94 684 1 +240 684 1 +438 684 1 +23 685 1 +277 685 1 +293 685 1 +93 686 1 +114 686 1 +245 686 1 +92 687 1 +102 687 1 +448 687 1 +408 688 1 +432 688 1 +461 688 1 +95 689 1 +139 689 1 +390 689 1 +229 690 1 +332 690 1 +415 690 1 +2 691 1 +278 691 1 +356 691 1 +25 692 1 +128 692 1 +482 692 1 +326 693 1 +411 693 1 +504 693 1 +62 694 1 +91 694 1 +284 694 1 +82 695 1 +317 695 1 +428 695 1 +166 696 1 +296 696 1 +378 696 1 +185 697 1 +265 697 1 +268 697 1 +7 698 1 +343 698 1 +400 698 1 +170 699 1 +291 699 1 +308 699 1 +15 700 1 +217 700 1 +468 700 1 +30 701 1 +124 701 1 +416 701 1 +216 702 1 +350 702 1 +393 702 1 +93 703 1 +220 703 1 +394 703 1 +94 704 1 +242 704 1 +405 704 1 +186 705 1 +220 705 1 +355 705 1 +24 706 1 +62 706 1 +408 706 1 +124 707 1 +233 707 1 +438 707 1 +268 708 1 +300 708 1 +323 708 1 +36 709 1 +190 709 1 +424 709 1 +108 710 1 +393 710 1 +401 710 1 +156 711 1 +445 711 1 +483 711 1 +448 712 1 +513 712 1 +516 712 1 +65 713 1 +478 713 1 +493 713 1 +134 714 1 +346 714 1 +362 714 1 +356 715 1 +375 715 1 +424 715 1 +79 716 1 +131 716 1 +372 716 1 +91 717 1 +99 717 1 +234 717 1 +165 718 1 +272 718 1 +515 718 1 +63 719 1 +160 719 1 +386 719 1 +30 720 1 +355 720 1 +382 720 1 +123 721 1 +279 721 1 +500 721 1 +56 722 1 +112 722 1 +314 722 1 +164 723 1 +305 723 1 +402 723 1 +97 724 1 +107 724 1 +425 724 1 +348 725 1 +403 725 1 +460 725 1 +262 726 1 +336 726 1 +456 726 1 +72 727 1 +109 727 1 +172 727 1 +294 728 1 +322 728 1 +501 728 1 +3 729 1 +143 729 1 +247 729 1 +33 730 1 +371 730 1 +495 730 1 +36 731 1 +147 731 1 +173 731 1 +143 732 1 +204 732 1 +492 732 1 +79 733 1 +192 733 1 +226 733 1 +31 734 1 +308 734 1 +476 734 1 +158 735 1 +180 735 1 +439 735 1 +124 736 1 +279 736 1 +346 736 1 +46 737 1 +127 737 1 +293 737 1 +131 738 1 +194 738 1 +353 738 1 +115 739 1 +145 739 1 +317 739 1 +103 740 1 +239 740 1 +435 740 1 +33 741 1 +124 741 1 +152 741 1 +280 742 1 +288 742 1 +487 742 1 +22 743 1 +24 743 1 +119 743 1 +69 744 1 +177 744 1 +348 744 1 +80 745 1 +191 745 1 +424 745 1 +343 746 1 +433 746 1 +499 746 1 +386 747 1 +429 747 1 +494 747 1 +295 748 1 +308 748 1 +495 748 1 +107 749 1 +270 749 1 +469 749 1 +39 750 1 +136 750 1 +251 750 1 +122 751 1 +330 751 1 +501 751 1 +18 752 1 +73 752 1 +401 752 1 +215 753 1 +469 753 1 +516 753 1 +78 754 1 +302 754 1 +308 754 1 +166 755 1 +274 755 1 +457 755 1 +136 756 1 +221 756 1 +280 756 1 +163 757 1 +246 757 1 +454 757 1 +222 758 1 +393 758 1 +440 758 1 +5 759 1 +328 759 1 +432 759 1 +405 760 1 +431 760 1 +470 760 1 +196 761 1 +454 761 1 +497 761 1 +253 762 1 +391 762 1 +399 762 1 +401 763 1 +426 763 1 +451 763 1 +78 764 1 +269 764 1 +344 764 1 +138 765 1 +434 765 1 +487 765 1 +184 766 1 +329 766 1 +432 766 1 +190 767 1 +245 767 1 +439 767 1 +131 768 1 +149 768 1 +516 768 1 +5 769 1 +151 769 1 +278 769 1 +141 770 1 +338 770 1 +461 770 1 +91 771 1 +328 771 1 +462 771 1 +84 772 1 +299 772 1 +313 772 1 +10 773 1 +433 773 1 +475 773 1 +210 774 1 +374 774 1 +386 774 1 +184 775 1 +230 775 1 +233 775 1 +171 776 1 +202 776 1 +396 776 1 +39 777 1 +472 777 1 +475 777 1 +20 778 1 +177 778 1 +439 778 1 +283 779 1 +360 779 1 +424 779 1 +92 780 1 +402 780 1 +495 780 1 +337 781 1 +387 781 1 +431 781 1 +257 782 1 +316 782 1 +434 782 1 +172 783 1 +181 783 1 +433 783 1 +160 784 1 +418 784 1 +436 784 1 +28 785 1 +52 785 1 +456 785 1 +134 786 1 +198 786 1 +403 786 1 +170 787 1 +174 787 1 +341 787 1 +18 788 1 +20 788 1 +423 788 1 +110 789 1 +197 789 1 +359 789 1 +108 790 1 +110 790 1 +296 790 1 +85 791 1 +294 791 1 +324 791 1 +21 792 1 +268 792 1 +309 792 1 +62 793 1 +123 793 1 +480 793 1 +122 794 1 +151 794 1 +508 794 1 +23 795 1 +43 795 1 +435 795 1 +10 796 1 +87 796 1 +144 796 1 +128 797 1 +250 797 1 +478 797 1 +161 798 1 +237 798 1 +401 798 1 +152 799 1 +247 799 1 +358 799 1 +156 800 1 +233 800 1 +287 800 1 +65 801 1 +143 801 1 +484 801 1 +249 802 1 +367 802 1 +512 802 1 +124 803 1 +231 803 1 +443 803 1 +191 804 1 +339 804 1 +367 804 1 +282 805 1 +381 805 1 +459 805 1 +139 806 1 +141 806 1 +452 806 1 +220 807 1 +233 807 1 +445 807 1 +238 808 1 +355 808 1 +468 808 1 +24 809 1 +204 809 1 +316 809 1 +60 810 1 +225 810 1 +271 810 1 +66 811 1 +382 811 1 +514 811 1 +41 812 1 +208 812 1 +388 812 1 +196 813 1 +224 813 1 +448 813 1 +185 814 1 +206 814 1 +474 814 1 +68 815 1 +159 815 1 +413 815 1 +72 816 1 +87 816 1 +307 816 1 +51 817 1 +80 817 1 +86 817 1 +121 818 1 +275 818 1 +293 818 1 +12 819 1 +103 819 1 +320 819 1 +218 820 1 +365 820 1 +433 820 1 +13 821 1 +33 821 1 +302 821 1 +101 822 1 +374 822 1 +394 822 1 +89 823 1 +117 823 1 +222 823 1 +93 824 1 +145 824 1 +414 824 1 +298 825 1 +332 825 1 +344 825 1 +293 826 1 +368 826 1 +456 826 1 +197 827 1 +309 827 1 +356 827 1 +201 828 1 +297 828 1 +475 828 1 +332 829 1 +421 829 1 +468 829 1 +36 830 1 +63 830 1 +456 830 1 +128 831 1 +212 831 1 +426 831 1 +160 832 1 +213 832 1 +494 832 1 +182 833 1 +373 833 1 +428 833 1 +42 834 1 +107 834 1 +339 834 1 +19 835 1 +249 835 1 +288 835 1 +53 836 1 +247 836 1 +494 836 1 +259 837 1 +318 837 1 +448 837 1 +116 838 1 +242 838 1 +270 838 1 +331 839 1 +464 839 1 +504 839 1 +131 840 1 +312 840 1 +507 840 1 +84 841 1 +164 841 1 +381 841 1 +125 842 1 +240 842 1 +405 842 1 +43 843 1 +103 843 1 +379 843 1 +285 844 1 +328 844 1 +498 844 1 +79 845 1 +345 845 1 +469 845 1 +112 846 1 +262 846 1 +489 846 1 +66 847 1 +160 847 1 +247 847 1 +66 848 1 +209 848 1 +354 848 1 +288 849 1 +401 849 1 +445 849 1 +93 850 1 +325 850 1 +500 850 1 +93 851 1 +249 851 1 +467 851 1 +158 852 1 +186 852 1 +217 852 1 +87 853 1 +201 853 1 +277 853 1 +104 854 1 +112 854 1 +385 854 1 +134 855 1 +250 855 1 +318 855 1 +131 856 1 +262 856 1 +513 856 1 +156 857 1 +215 857 1 +218 857 1 +58 858 1 +70 858 1 +253 858 1 +33 859 1 +473 859 1 +483 859 1 +6 860 1 +170 860 1 +249 860 1 +42 861 1 +126 861 1 +325 861 1 +16 862 1 +143 862 1 +161 862 1 +130 863 1 +211 863 1 +351 863 1 +182 864 1 +313 864 1 +505 864 1 +354 865 1 +370 865 1 +475 865 1 +141 866 1 +183 866 1 +440 866 1 +12 867 1 +220 867 1 +229 867 1 +65 868 1 +174 868 1 +412 868 1 +60 869 1 +388 869 1 +461 869 1 +1 870 1 +346 870 1 +371 870 1 +169 871 1 +351 871 1 +427 871 1 +175 872 1 +182 872 1 +377 872 1 +82 873 1 +173 873 1 +439 873 1 +44 874 1 +48 874 1 +338 874 1 +82 875 1 +214 875 1 +473 875 1 +108 876 1 +370 876 1 +500 876 1 +17 877 1 +163 877 1 +292 877 1 +69 878 1 +92 878 1 +167 878 1 +28 879 1 +95 879 1 +315 879 1 +29 880 1 +228 880 1 +230 880 1 +80 881 1 +134 881 1 +261 881 1 +145 882 1 +461 882 1 +464 882 1 +25 883 1 +251 883 1 +294 883 1 +66 884 1 +398 884 1 +407 884 1 +88 885 1 +205 885 1 +226 885 1 +14 886 1 +282 886 1 +406 886 1 +64 887 1 +372 887 1 +488 887 1 +290 888 1 +363 888 1 +426 888 1 +160 889 1 +348 889 1 +432 889 1 +46 890 1 +83 890 1 +515 890 1 +113 891 1 +321 891 1 +511 891 1 +1 892 1 +175 892 1 +421 892 1 +251 893 1 +265 893 1 +489 893 1 +55 894 1 +160 894 1 +439 894 1 +61 895 1 +252 895 1 +282 895 1 +185 896 1 +479 896 1 +515 896 1 +199 897 1 +340 897 1 +483 897 1 +153 898 1 +257 898 1 +325 898 1 +13 899 1 +64 899 1 +323 899 1 +237 900 1 +285 900 1 +462 900 1 +150 901 1 +419 901 1 +443 901 1 +269 902 1 +369 902 1 +491 902 1 +5 903 1 +23 903 1 +377 903 1 +100 904 1 +196 904 1 +384 904 1 +126 905 1 +283 905 1 +349 905 1 +243 906 1 +286 906 1 +491 906 1 +312 907 1 +327 907 1 +353 907 1 +56 908 1 +97 908 1 +226 908 1 +219 909 1 +411 909 1 +420 909 1 +203 910 1 +331 910 1 +495 910 1 +156 911 1 +184 911 1 +428 911 1 +144 912 1 +297 912 1 +409 912 1 +164 913 1 +325 913 1 +473 913 1 +161 914 1 +284 914 1 +461 914 1 +87 915 1 +341 915 1 +357 915 1 +236 916 1 +245 916 1 +473 916 1 +203 917 1 +302 917 1 +371 917 1 +10 918 1 +294 918 1 +343 918 1 +216 919 1 +231 919 1 +360 919 1 +13 920 1 +247 920 1 +398 920 1 +166 921 1 +319 921 1 +500 921 1 +239 922 1 +404 922 1 +465 922 1 +19 923 1 +190 923 1 +401 923 1 +141 924 1 +180 924 1 +319 924 1 +51 925 1 +491 925 1 +513 925 1 +284 926 1 +441 926 1 +483 926 1 +61 927 1 +147 927 1 +216 927 1 +11 928 1 +303 928 1 +405 928 1 +75 929 1 +148 929 1 +424 929 1 +205 930 1 +291 930 1 +473 930 1 +31 931 1 +350 931 1 +455 931 1 +128 932 1 +471 932 1 +516 932 1 +49 933 1 +197 933 1 +235 933 1 +2 934 1 +396 934 1 +476 934 1 +33 935 1 +187 935 1 +308 935 1 +5 936 1 +92 936 1 +248 936 1 +135 937 1 +201 937 1 +281 937 1 +100 938 1 +269 938 1 +482 938 1 +194 939 1 +200 939 1 +244 939 1 +78 940 1 +264 940 1 +481 940 1 +154 941 1 +250 941 1 +407 941 1 +245 942 1 +338 942 1 +345 942 1 +51 943 1 +104 943 1 +309 943 1 +321 944 1 +470 944 1 +506 944 1 +121 945 1 +379 945 1 +417 945 1 +160 946 1 +248 946 1 +485 946 1 +114 947 1 +168 947 1 +363 947 1 +74 948 1 +271 948 1 +320 948 1 +44 949 1 +113 949 1 +192 949 1 +113 950 1 +146 950 1 +470 950 1 +59 951 1 +205 951 1 +231 951 1 +259 952 1 +267 952 1 +513 952 1 +6 953 1 +71 953 1 +246 953 1 +49 954 1 +296 954 1 +299 954 1 +144 955 1 +221 955 1 +447 955 1 +6 956 1 +385 956 1 +467 956 1 +22 957 1 +153 957 1 +163 957 1 +214 958 1 +347 958 1 +510 958 1 +171 959 1 +482 959 1 +498 959 1 +98 960 1 +252 960 1 +337 960 1 +181 961 1 +339 961 1 +417 961 1 +225 962 1 +453 962 1 +491 962 1 +368 963 1 +390 963 1 +457 963 1 +8 964 1 +289 964 1 +422 964 1 +274 965 1 +284 965 1 +340 965 1 +154 966 1 +229 966 1 +422 966 1 +262 967 1 +269 967 1 +298 967 1 +234 968 1 +263 968 1 +273 968 1 +21 969 1 +167 969 1 +301 969 1 +19 970 1 +27 970 1 +447 970 1 +352 971 1 +369 971 1 +449 971 1 +9 972 1 +80 972 1 +356 972 1 +165 973 1 +243 973 1 +374 973 1 +20 974 1 +432 974 1 +436 974 1 +90 975 1 +230 975 1 +299 975 1 +85 976 1 +153 976 1 +225 976 1 +255 977 1 +280 977 1 +452 977 1 +367 978 1 +397 978 1 +468 978 1 +174 979 1 +239 979 1 +490 979 1 +29 980 1 +380 980 1 +403 980 1 +145 981 1 +208 981 1 +432 981 1 +43 982 1 +244 982 1 +387 982 1 +1 983 1 +8 983 1 +38 983 1 +3 984 1 +72 984 1 +277 984 1 +153 985 1 +271 985 1 +340 985 1 +10 986 1 +354 986 1 +514 986 1 +280 987 1 +328 987 1 +485 987 1 +77 988 1 +233 988 1 +355 988 1 +221 989 1 +224 989 1 +253 989 1 +12 990 1 +297 990 1 +400 990 1 +11 991 1 +297 991 1 +389 991 1 +142 992 1 +204 992 1 +460 992 1 +370 993 1 +461 993 1 +492 993 1 +143 994 1 +190 994 1 +356 994 1 +116 995 1 +259 995 1 +300 995 1 +145 996 1 +151 996 1 +400 996 1 +223 997 1 +306 997 1 +404 997 1 +330 998 1 +375 998 1 +404 998 1 +36 999 1 +195 999 1 +498 999 1 +9 1000 1 +189 1000 1 +369 1000 1 +157 1001 1 +304 1001 1 +330 1001 1 +99 1002 1 +155 1002 1 +273 1002 1 +271 1003 1 +279 1003 1 +311 1003 1 +88 1004 1 +232 1004 1 +248 1004 1 +291 1005 1 +352 1005 1 +491 1005 1 +49 1006 1 +123 1006 1 +126 1006 1 +89 1007 1 +177 1007 1 +216 1007 1 +47 1008 1 +339 1008 1 +495 1008 1 +94 1009 1 +401 1009 1 +449 1009 1 +394 1010 1 +493 1010 1 +505 1010 1 +344 1011 1 +384 1011 1 +407 1011 1 +305 1012 1 +376 1012 1 +380 1012 1 +38 1013 1 +340 1013 1 +425 1013 1 +30 1014 1 +38 1014 1 +246 1014 1 +39 1015 1 +171 1015 1 +437 1015 1 +6 1016 1 +79 1016 1 +153 1016 1 +129 1017 1 +161 1017 1 +211 1017 1 +1 1018 1 +78 1018 1 +256 1018 1 +242 1019 1 +340 1019 1 +387 1019 1 +268 1020 1 +293 1020 1 +515 1020 1 +200 1021 1 +238 1021 1 +297 1021 1 +298 1022 1 +465 1022 1 +507 1022 1 +182 1023 1 +191 1023 1 +440 1023 1 +297 1024 1 +435 1024 1 +480 1024 1 +175 1025 1 +179 1025 1 +361 1025 1 +27 1026 1 +244 1026 1 +412 1026 1 +117 1027 1 +387 1027 1 +395 1027 1 +135 1028 1 +184 1028 1 +431 1028 1 +108 1029 1 +211 1029 1 +412 1029 1 +246 1030 1 +307 1030 1 +371 1030 1 +60 1031 1 +352 1031 1 +506 1031 1 +38 1032 1 +342 1032 1 +435 1032 1 +225 1033 1 +316 1033 1 +421 1033 1 +48 1034 1 +196 1034 1 +462 1034 1 +12 1035 1 +351 1035 1 +504 1035 1 +124 1036 1 +353 1036 1 +483 1036 1 +229 1037 1 +445 1037 1 +472 1037 1 +55 1038 1 +69 1038 1 +436 1038 1 +50 1039 1 +97 1039 1 +507 1039 1 +311 1040 1 +368 1040 1 +370 1040 1 +70 1041 1 +180 1041 1 +183 1041 1 +133 1042 1 +274 1042 1 +485 1042 1 +119 1043 1 +136 1043 1 +330 1043 1 +151 1044 1 +275 1044 1 +389 1044 1 +199 1045 1 +342 1045 1 +381 1045 1 +73 1046 1 +189 1046 1 +473 1046 1 +70 1047 1 +75 1047 1 +272 1047 1 +98 1048 1 +395 1048 1 +449 1048 1 +26 1049 1 +145 1049 1 +364 1049 1 +76 1050 1 +147 1050 1 +192 1050 1 +99 1051 1 +205 1051 1 +345 1051 1 +154 1052 1 +185 1052 1 +312 1052 1 +112 1053 1 +222 1053 1 +252 1053 1 +76 1054 1 +218 1054 1 +333 1054 1 +236 1055 1 +413 1055 1 +501 1055 1 +273 1056 1 +297 1056 1 +388 1056 1 +22 1057 1 +374 1057 1 +491 1057 1 +109 1058 1 +144 1058 1 +246 1058 1 +206 1059 1 +453 1059 1 +507 1059 1 +61 1060 1 +372 1060 1 +393 1060 1 +34 1061 1 +138 1061 1 +355 1061 1 +146 1062 1 +302 1062 1 +358 1062 1 +292 1063 1 +316 1063 1 +367 1063 1 +132 1064 1 +237 1064 1 +417 1064 1 +254 1065 1 +356 1065 1 +499 1065 1 +42 1066 1 +46 1066 1 +81 1066 1 +1 1067 1 +40 1067 1 +516 1067 1 +121 1068 1 +339 1068 1 +494 1068 1 +310 1069 1 +343 1069 1 +490 1069 1 +33 1070 1 +184 1070 1 +228 1070 1 +41 1071 1 +242 1071 1 +480 1071 1 +49 1072 1 +125 1072 1 +367 1072 1 +168 1073 1 +216 1073 1 +427 1073 1 +226 1074 1 +345 1074 1 +387 1074 1 +247 1075 1 +305 1075 1 +349 1075 1 +459 1076 1 +477 1076 1 +510 1076 1 +47 1077 1 +148 1077 1 +349 1077 1 +211 1078 1 +214 1078 1 +411 1078 1 +187 1079 1 +199 1079 1 +321 1079 1 +41 1080 1 +303 1080 1 +449 1080 1 +58 1081 1 +306 1081 1 +315 1081 1 +8 1082 1 +123 1082 1 +307 1082 1 +388 1083 1 +440 1083 1 +458 1083 1 +359 1084 1 +404 1084 1 +490 1084 1 +129 1085 1 +292 1085 1 +462 1085 1 +83 1086 1 +210 1086 1 +323 1086 1 +129 1087 1 +328 1087 1 +406 1087 1 +190 1088 1 +350 1088 1 +452 1088 1 +55 1089 1 +210 1089 1 +456 1089 1 +189 1090 1 +337 1090 1 +357 1090 1 +48 1091 1 +94 1091 1 +153 1091 1 +258 1092 1 +309 1092 1 +359 1092 1 +60 1093 1 +408 1093 1 +503 1093 1 +58 1094 1 +151 1094 1 +375 1094 1 +13 1095 1 +76 1095 1 +352 1095 1 +205 1096 1 +276 1096 1 +385 1096 1 +263 1097 1 +266 1097 1 +392 1097 1 +232 1098 1 +325 1098 1 +442 1098 1 +151 1099 1 +482 1099 1 +485 1099 1 +96 1100 1 +155 1100 1 +260 1100 1 +77 1101 1 +332 1101 1 +445 1101 1 +31 1102 1 +254 1102 1 +423 1102 1 +53 1103 1 +209 1103 1 +512 1103 1 +64 1104 1 +321 1104 1 +410 1104 1 +174 1105 1 +297 1105 1 +361 1105 1 +197 1106 1 +243 1106 1 +396 1106 1 +200 1107 1 +355 1107 1 +421 1107 1 +25 1108 1 +259 1108 1 +514 1108 1 +93 1109 1 +164 1109 1 +300 1109 1 +191 1110 1 +221 1110 1 +412 1110 1 +139 1111 1 +453 1111 1 +487 1111 1 +217 1112 1 +361 1112 1 +489 1112 1 +5 1113 1 +15 1113 1 +19 1113 1 +117 1114 1 +338 1114 1 +352 1114 1 +51 1115 1 +357 1115 1 +447 1115 1 +212 1116 1 +289 1116 1 +347 1116 1 +72 1117 1 +240 1117 1 +321 1117 1 +28 1118 1 +149 1118 1 +400 1118 1 +2 1119 1 +249 1119 1 +394 1119 1 +236 1120 1 +263 1120 1 +284 1120 1 +114 1121 1 +219 1121 1 +510 1121 1 +320 1122 1 +447 1122 1 +508 1122 1 +35 1123 1 +434 1123 1 +502 1123 1 +106 1124 1 +261 1124 1 +281 1124 1 +74 1125 1 +300 1125 1 +459 1125 1 +28 1126 1 +159 1126 1 +177 1126 1 +425 1127 1 +479 1127 1 +483 1127 1 +282 1128 1 +342 1128 1 +388 1128 1 +49 1129 1 +93 1129 1 +399 1129 1 +132 1130 1 +213 1130 1 +379 1130 1 +2 1131 1 +57 1131 1 +180 1131 1 +82 1132 1 +141 1132 1 +186 1132 1 +47 1133 1 +177 1133 1 +209 1133 1 +143 1134 1 +335 1134 1 +502 1134 1 +142 1135 1 +410 1135 1 +418 1135 1 +100 1136 1 +315 1136 1 +326 1136 1 +25 1137 1 +188 1137 1 +214 1137 1 +79 1138 1 +166 1138 1 +432 1138 1 +43 1139 1 +223 1139 1 +274 1139 1 +24 1140 1 +307 1140 1 +401 1140 1 +23 1141 1 +354 1141 1 +413 1141 1 +399 1142 1 +492 1142 1 +512 1142 1 +92 1143 1 +170 1143 1 +322 1143 1 +97 1144 1 +187 1144 1 +264 1144 1 +290 1145 1 +453 1145 1 +513 1145 1 +31 1146 1 +195 1146 1 +239 1146 1 +69 1147 1 +127 1147 1 +501 1147 1 +109 1148 1 +349 1148 1 +464 1148 1 +165 1149 1 +410 1149 1 +419 1149 1 +83 1150 1 +151 1150 1 +259 1150 1 +41 1151 1 +207 1151 1 +418 1151 1 +98 1152 1 +130 1152 1 +306 1152 1 +84 1153 1 +147 1153 1 +307 1153 1 +195 1154 1 +216 1154 1 +319 1154 1 +319 1155 1 +417 1155 1 +484 1155 1 +347 1156 1 +439 1156 1 +512 1156 1 +222 1157 1 +369 1157 1 +453 1157 1 +37 1158 1 +83 1158 1 +363 1158 1 +39 1159 1 +461 1159 1 +508 1159 1 +104 1160 1 +326 1160 1 +454 1160 1 +5 1161 1 +406 1161 1 +424 1161 1 +196 1162 1 +381 1162 1 +450 1162 1 +207 1163 1 +227 1163 1 +275 1163 1 +47 1164 1 +126 1164 1 +270 1164 1 +4 1165 1 +270 1165 1 +301 1165 1 +223 1166 1 +258 1166 1 +260 1166 1 +141 1167 1 +394 1167 1 +512 1167 1 +32 1168 1 +108 1168 1 +161 1168 1 +47 1169 1 +331 1169 1 +494 1169 1 +81 1170 1 +228 1170 1 +323 1170 1 +96 1171 1 +333 1171 1 +346 1171 1 +31 1172 1 +72 1172 1 +189 1172 1 +68 1173 1 +95 1173 1 +348 1173 1 +101 1174 1 +209 1174 1 +376 1174 1 +145 1175 1 +319 1175 1 +345 1175 1 +177 1176 1 +351 1176 1 +464 1176 1 +85 1177 1 +346 1177 1 +421 1177 1 +129 1178 1 +379 1178 1 +381 1178 1 +271 1179 1 +284 1179 1 +342 1179 1 +334 1180 1 +392 1180 1 +464 1180 1 +224 1181 1 +315 1181 1 +359 1181 1 +36 1182 1 +191 1182 1 +455 1182 1 +117 1183 1 +147 1183 1 +492 1183 1 +56 1184 1 +463 1184 1 +470 1184 1 +70 1185 1 +95 1185 1 +359 1185 1 +410 1186 1 +486 1186 1 +505 1186 1 +212 1187 1 +415 1187 1 +465 1187 1 +87 1188 1 +167 1188 1 +343 1188 1 +298 1189 1 +324 1189 1 +420 1189 1 +361 1190 1 +377 1190 1 +435 1190 1 +160 1191 1 +390 1191 1 +428 1191 1 +164 1192 1 +375 1192 1 +510 1192 1 +34 1193 1 +410 1193 1 +478 1193 1 +19 1194 1 +92 1194 1 +193 1194 1 +52 1195 1 +354 1195 1 +419 1195 1 +66 1196 1 +106 1196 1 +380 1196 1 +310 1197 1 +364 1197 1 +414 1197 1 +4 1198 1 +106 1198 1 +181 1198 1 +105 1199 1 +370 1199 1 +394 1199 1 +40 1200 1 +132 1200 1 +266 1200 1 +180 1201 1 +193 1201 1 +396 1201 1 +137 1202 1 +396 1202 1 +491 1202 1 +263 1203 1 +321 1203 1 +395 1203 1 +37 1204 1 +134 1204 1 +192 1204 1 +73 1205 1 +119 1205 1 +421 1205 1 +237 1206 1 +393 1206 1 +404 1206 1 +29 1207 1 +327 1207 1 +507 1207 1 +135 1208 1 +195 1208 1 +456 1208 1 +20 1209 1 +506 1209 1 +512 1209 1 +7 1210 1 +30 1210 1 +251 1210 1 +336 1211 1 +341 1211 1 +384 1211 1 +197 1212 1 +253 1212 1 +442 1212 1 +68 1213 1 +233 1213 1 +421 1213 1 +2 1214 1 +82 1214 1 +334 1214 1 +131 1215 1 +283 1215 1 +384 1215 1 +28 1216 1 +55 1216 1 +317 1216 1 +60 1217 1 +207 1217 1 +320 1217 1 +88 1218 1 +301 1218 1 +391 1218 1 +94 1219 1 +430 1219 1 +477 1219 1 +58 1220 1 +167 1220 1 +171 1220 1 +83 1221 1 +248 1221 1 +336 1221 1 +38 1222 1 +163 1222 1 +273 1222 1 +218 1223 1 +475 1223 1 +500 1223 1 +7 1224 1 +77 1224 1 +446 1224 1 +1 1225 1 +218 1225 1 +414 1225 1 +71 1226 1 +124 1226 1 +340 1226 1 +296 1227 1 +367 1227 1 +484 1227 1 +149 1228 1 +176 1228 1 +306 1228 1 +355 1229 1 +415 1229 1 +453 1229 1 +146 1230 1 +426 1230 1 +445 1230 1 +179 1231 1 +188 1231 1 +327 1231 1 +64 1232 1 +380 1232 1 +405 1232 1 +2 1233 1 +58 1233 1 +406 1233 1 +418 1234 1 +488 1234 1 +506 1234 1 +155 1235 1 +209 1235 1 +236 1235 1 +127 1236 1 +170 1236 1 +491 1236 1 +76 1237 1 +164 1237 1 +371 1237 1 +348 1238 1 +354 1238 1 +508 1238 1 +54 1239 1 +134 1239 1 +471 1239 1 +83 1240 1 +212 1240 1 +446 1240 1 +251 1241 1 +334 1241 1 +501 1241 1 +48 1242 1 +255 1242 1 +290 1242 1 +27 1243 1 +220 1243 1 +366 1243 1 +185 1244 1 +349 1244 1 +507 1244 1 +32 1245 1 +110 1245 1 +250 1245 1 +84 1246 1 +288 1246 1 +394 1246 1 +4 1247 1 +227 1247 1 +403 1247 1 +89 1248 1 +350 1248 1 +458 1248 1 +107 1249 1 +201 1249 1 +266 1249 1 +360 1250 1 +406 1250 1 +509 1250 1 +257 1251 1 +319 1251 1 +351 1251 1 +29 1252 1 +442 1252 1 +493 1252 1 +54 1253 1 +117 1253 1 +252 1253 1 +318 1254 1 +330 1254 1 +510 1254 1 +56 1255 1 +228 1255 1 +456 1255 1 +95 1256 1 +148 1256 1 +176 1256 1 +295 1257 1 +424 1257 1 +440 1257 1 +51 1258 1 +267 1258 1 +419 1258 1 +45 1259 1 +155 1259 1 +378 1259 1 +47 1260 1 +452 1260 1 +506 1260 1 +24 1261 1 +161 1261 1 +399 1261 1 +256 1262 1 +345 1262 1 +442 1262 1 +173 1263 1 +217 1263 1 +319 1263 1 +92 1264 1 +474 1264 1 +514 1264 1 +154 1265 1 +179 1265 1 +462 1265 1 +63 1266 1 +208 1266 1 +275 1266 1 +255 1267 1 +328 1267 1 +459 1267 1 +321 1268 1 +367 1268 1 +378 1268 1 +132 1269 1 +254 1269 1 +350 1269 1 +76 1270 1 +173 1270 1 +226 1270 1 +116 1271 1 +210 1271 1 +494 1271 1 +92 1272 1 +259 1272 1 +430 1272 1 +308 1273 1 +458 1273 1 +494 1273 1 +20 1274 1 +296 1274 1 +394 1274 1 +52 1275 1 +277 1275 1 +486 1275 1 +178 1276 1 +206 1276 1 +442 1276 1 +292 1277 1 +296 1277 1 +381 1277 1 +87 1278 1 +162 1278 1 +233 1278 1 +216 1279 1 +480 1279 1 +500 1279 1 +275 1280 1 +430 1280 1 +504 1280 1 +16 1281 1 +183 1281 1 +504 1281 1 +152 1282 1 +202 1282 1 +308 1282 1 +151 1283 1 +268 1283 1 +494 1283 1 +165 1284 1 +263 1284 1 +366 1284 1 +226 1285 1 +274 1285 1 +353 1285 1 +276 1286 1 +312 1286 1 +469 1286 1 +36 1287 1 +374 1287 1 +439 1287 1 +1 1288 1 +96 1288 1 +463 1288 1 +333 1289 1 +445 1289 1 +516 1289 1 +30 1290 1 +66 1290 1 +109 1290 1 +428 1291 1 +463 1291 1 +473 1291 1 +17 1292 1 +321 1292 1 +473 1292 1 +136 1293 1 +250 1293 1 +343 1293 1 +11 1294 1 +204 1294 1 +383 1294 1 +192 1295 1 +194 1295 1 +435 1295 1 +45 1296 1 +129 1296 1 +282 1296 1 +40 1297 1 +78 1297 1 +509 1297 1 +34 1298 1 +342 1298 1 +420 1298 1 +268 1299 1 +485 1299 1 +514 1299 1 +68 1300 1 +289 1300 1 +333 1300 1 +292 1301 1 +387 1301 1 +450 1301 1 +54 1302 1 +67 1302 1 +307 1302 1 +85 1303 1 +119 1303 1 +477 1303 1 +120 1304 1 +256 1304 1 +375 1304 1 +116 1305 1 +241 1305 1 +398 1305 1 +206 1306 1 +341 1306 1 +466 1306 1 +92 1307 1 +110 1307 1 +382 1307 1 +99 1308 1 +215 1308 1 +479 1308 1 +213 1309 1 +276 1309 1 +452 1309 1 +91 1310 1 +226 1310 1 +283 1310 1 +15 1311 1 +186 1311 1 +285 1311 1 +14 1312 1 +276 1312 1 +495 1312 1 +43 1313 1 +266 1313 1 +482 1313 1 +112 1314 1 +198 1314 1 +425 1314 1 +305 1315 1 +331 1315 1 +430 1315 1 +319 1316 1 +455 1316 1 +505 1316 1 +157 1317 1 +167 1317 1 +322 1317 1 +136 1318 1 +232 1318 1 +444 1318 1 +76 1319 1 +89 1319 1 +503 1319 1 +25 1320 1 +355 1320 1 +497 1320 1 +141 1321 1 +166 1321 1 +449 1321 1 +95 1322 1 +336 1322 1 +486 1322 1 +82 1323 1 +147 1323 1 +338 1323 1 +11 1324 1 +397 1324 1 +440 1324 1 +32 1325 1 +167 1325 1 +355 1325 1 +41 1326 1 +260 1326 1 +488 1326 1 +74 1327 1 +175 1327 1 +413 1327 1 +49 1328 1 +282 1328 1 +352 1328 1 +301 1329 1 +465 1329 1 +513 1329 1 +122 1330 1 +265 1330 1 +331 1330 1 +128 1331 1 +178 1331 1 +333 1331 1 +338 1332 1 +453 1332 1 +506 1332 1 +94 1333 1 +189 1333 1 +423 1333 1 +129 1334 1 +132 1334 1 +183 1334 1 +265 1335 1 +273 1335 1 +361 1335 1 +71 1336 1 +202 1336 1 +474 1336 1 +11 1337 1 +132 1337 1 +461 1337 1 +109 1338 1 +209 1338 1 +409 1338 1 +22 1339 1 +62 1339 1 +425 1339 1 +328 1340 1 +400 1340 1 +411 1340 1 +13 1341 1 +397 1341 1 +481 1341 1 +105 1342 1 +114 1342 1 +397 1342 1 +22 1343 1 +225 1343 1 +470 1343 1 +196 1344 1 +299 1344 1 +332 1344 1 +240 1345 1 +288 1345 1 +395 1345 1 +198 1346 1 +259 1346 1 +343 1346 1 +7 1347 1 +228 1347 1 +298 1347 1 +146 1348 1 +149 1348 1 +159 1348 1 +181 1349 1 +319 1349 1 +476 1349 1 +115 1350 1 +160 1350 1 +512 1350 1 +62 1351 1 +327 1351 1 +398 1351 1 +61 1352 1 +406 1352 1 +444 1352 1 +218 1353 1 +411 1353 1 +516 1353 1 +64 1354 1 +217 1354 1 +505 1354 1 +170 1355 1 +374 1355 1 +499 1355 1 +222 1356 1 +286 1356 1 +397 1356 1 +15 1357 1 +229 1357 1 +421 1357 1 +99 1358 1 +236 1358 1 +271 1358 1 +36 1359 1 +129 1359 1 +130 1359 1 +31 1360 1 +232 1360 1 +424 1360 1 +258 1361 1 +403 1361 1 +456 1361 1 +69 1362 1 +266 1362 1 +270 1362 1 +41 1363 1 +432 1363 1 +463 1363 1 +56 1364 1 +189 1364 1 +431 1364 1 +60 1365 1 +115 1365 1 +334 1365 1 +129 1366 1 +338 1366 1 +397 1366 1 +33 1367 1 +120 1367 1 +399 1367 1 +103 1368 1 +342 1368 1 +509 1368 1 +57 1369 1 +197 1369 1 +335 1369 1 +21 1370 1 +248 1370 1 +341 1370 1 +103 1371 1 +310 1371 1 +443 1371 1 +127 1372 1 +269 1372 1 +392 1372 1 +165 1373 1 +298 1373 1 +509 1373 1 +13 1374 1 +79 1374 1 +338 1374 1 +39 1375 1 +156 1375 1 +284 1375 1 +328 1376 1 +453 1376 1 +468 1376 1 +105 1377 1 +325 1377 1 +382 1377 1 +228 1378 1 +468 1378 1 +477 1378 1 +107 1379 1 +116 1379 1 +443 1379 1 +120 1380 1 +246 1380 1 +331 1380 1 +86 1381 1 +210 1381 1 +455 1381 1 +98 1382 1 +438 1382 1 +445 1382 1 +27 1383 1 +43 1383 1 +169 1383 1 +54 1384 1 +256 1384 1 +296 1384 1 +205 1385 1 +378 1385 1 +511 1385 1 +167 1386 1 +294 1386 1 +491 1386 1 +244 1387 1 +398 1387 1 +408 1387 1 +74 1388 1 +84 1388 1 +427 1388 1 +238 1389 1 +366 1389 1 +408 1389 1 +38 1390 1 +122 1390 1 +318 1390 1 +89 1391 1 +311 1391 1 +405 1391 1 +5 1392 1 +174 1392 1 +182 1392 1 +120 1393 1 +346 1393 1 +392 1393 1 +329 1394 1 +377 1394 1 +390 1394 1 +37 1395 1 +320 1395 1 +488 1395 1 +37 1396 1 +111 1396 1 +219 1396 1 +278 1397 1 +309 1397 1 +368 1397 1 +24 1398 1 +243 1398 1 +369 1398 1 +140 1399 1 +162 1399 1 +384 1399 1 +118 1400 1 +329 1400 1 +372 1400 1 +127 1401 1 +165 1401 1 +336 1401 1 +203 1402 1 +307 1402 1 +399 1402 1 +23 1403 1 +229 1403 1 +502 1403 1 +106 1404 1 +266 1404 1 +515 1404 1 +286 1405 1 +305 1405 1 +356 1405 1 +243 1406 1 +267 1406 1 +486 1406 1 +72 1407 1 +94 1407 1 +325 1407 1 +152 1408 1 +230 1408 1 +293 1408 1 +86 1409 1 +454 1409 1 +504 1409 1 +61 1410 1 +131 1410 1 +162 1410 1 +22 1411 1 +72 1411 1 +451 1411 1 +11 1412 1 +50 1412 1 +295 1412 1 +6 1413 1 +209 1413 1 +339 1413 1 +34 1414 1 +199 1414 1 +220 1414 1 +256 1415 1 +283 1415 1 +471 1415 1 +269 1416 1 +329 1416 1 +421 1416 1 +158 1417 1 +178 1417 1 +351 1417 1 +175 1418 1 +400 1418 1 +433 1418 1 +211 1419 1 +236 1419 1 +334 1419 1 +317 1420 1 +388 1420 1 +392 1420 1 +253 1421 1 +423 1421 1 +465 1421 1 +50 1422 1 +127 1422 1 +303 1422 1 +50 1423 1 +190 1423 1 +418 1423 1 +27 1424 1 +287 1424 1 +306 1424 1 +130 1425 1 +175 1425 1 +316 1425 1 +454 1426 1 +477 1426 1 +515 1426 1 +41 1427 1 +274 1427 1 +317 1427 1 +250 1428 1 +314 1428 1 +438 1428 1 +267 1429 1 +465 1429 1 +482 1429 1 +144 1430 1 +389 1430 1 +454 1430 1 +303 1431 1 +410 1431 1 +475 1431 1 +11 1432 1 +350 1432 1 +370 1432 1 +104 1433 1 +131 1433 1 +459 1433 1 +63 1434 1 +263 1434 1 +496 1434 1 +18 1435 1 +108 1435 1 +505 1435 1 +124 1436 1 +201 1436 1 +384 1436 1 +104 1437 1 +127 1437 1 +185 1437 1 +58 1438 1 +130 1438 1 +172 1438 1 +140 1439 1 +468 1439 1 +497 1439 1 +25 1440 1 +59 1440 1 +171 1440 1 +151 1441 1 +223 1441 1 +281 1441 1 +58 1442 1 +148 1442 1 +400 1442 1 +239 1443 1 +341 1443 1 +418 1443 1 +286 1444 1 +336 1444 1 +499 1444 1 +155 1445 1 +414 1445 1 +436 1445 1 +217 1446 1 +235 1446 1 +391 1446 1 +27 1447 1 +36 1447 1 +108 1447 1 +182 1448 1 +288 1448 1 +468 1448 1 +10 1449 1 +171 1449 1 +280 1449 1 +398 1450 1 +405 1450 1 +422 1450 1 +65 1451 1 +111 1451 1 +313 1451 1 +190 1452 1 +395 1452 1 +467 1452 1 +81 1453 1 +271 1453 1 +398 1453 1 +69 1454 1 +122 1454 1 +464 1454 1 +119 1455 1 +154 1455 1 +167 1455 1 +78 1456 1 +150 1456 1 +254 1456 1 +20 1457 1 +164 1457 1 +168 1457 1 +136 1458 1 +403 1458 1 +448 1458 1 +106 1459 1 +460 1459 1 +465 1459 1 +51 1460 1 +374 1460 1 +505 1460 1 +188 1461 1 +213 1461 1 +471 1461 1 +200 1462 1 +208 1462 1 +312 1462 1 +350 1463 1 +464 1463 1 +467 1463 1 +303 1464 1 +310 1464 1 +418 1464 1 +133 1465 1 +143 1465 1 +403 1465 1 +53 1466 1 +356 1466 1 +374 1466 1 +73 1467 1 +204 1467 1 +470 1467 1 +15 1468 1 +81 1468 1 +459 1468 1 +158 1469 1 +273 1469 1 +347 1469 1 +262 1470 1 +314 1470 1 +468 1470 1 +150 1471 1 +287 1471 1 +395 1471 1 +192 1472 1 +380 1472 1 +425 1472 1 +10 1473 1 +16 1473 1 +19 1473 1 +289 1474 1 +410 1474 1 +472 1474 1 +162 1475 1 +313 1475 1 +510 1475 1 +362 1476 1 +385 1476 1 +456 1476 1 +234 1477 1 +410 1477 1 +428 1477 1 +232 1478 1 +406 1478 1 +495 1478 1 +16 1479 1 +23 1479 1 +75 1479 1 +225 1480 1 +240 1480 1 +255 1480 1 +334 1481 1 +370 1481 1 +467 1481 1 +294 1482 1 +373 1482 1 +465 1482 1 +6 1483 1 +416 1483 1 +425 1483 1 +105 1484 1 +355 1484 1 +512 1484 1 +125 1485 1 +204 1485 1 +387 1485 1 +68 1486 1 +176 1486 1 +426 1486 1 +72 1487 1 +187 1487 1 +335 1487 1 +176 1488 1 +329 1488 1 +453 1488 1 +239 1489 1 +357 1489 1 +474 1489 1 +20 1490 1 +292 1490 1 +487 1490 1 +163 1491 1 +282 1491 1 +480 1491 1 +353 1492 1 +384 1492 1 +462 1492 1 +118 1493 1 +212 1493 1 +344 1493 1 +117 1494 1 +273 1494 1 +511 1494 1 +170 1495 1 +202 1495 1 +207 1495 1 +90 1496 1 +262 1496 1 +309 1496 1 +258 1497 1 +385 1497 1 +419 1497 1 +50 1498 1 +198 1498 1 +419 1498 1 +45 1499 1 +191 1499 1 +395 1499 1 +88 1500 1 +402 1500 1 +424 1500 1 +87 1501 1 +230 1501 1 +272 1501 1 +128 1502 1 +266 1502 1 +346 1502 1 +85 1503 1 +179 1503 1 +382 1503 1 +4 1504 1 +389 1504 1 +460 1504 1 +62 1505 1 +210 1505 1 +352 1505 1 +34 1506 1 +165 1506 1 +169 1506 1 +268 1507 1 +375 1507 1 +442 1507 1 +258 1508 1 +261 1508 1 +476 1508 1 +183 1509 1 +287 1509 1 +404 1509 1 +25 1510 1 +302 1510 1 +473 1510 1 +146 1511 1 +471 1511 1 +511 1511 1 +85 1512 1 +250 1512 1 +330 1512 1 +44 1513 1 +144 1513 1 +196 1513 1 +133 1514 1 +284 1514 1 +334 1514 1 +107 1515 1 +279 1515 1 +329 1515 1 +140 1516 1 +277 1516 1 +438 1516 1 +87 1517 1 +382 1517 1 +438 1517 1 +64 1518 1 +118 1518 1 +503 1518 1 +18 1519 1 +65 1519 1 +255 1519 1 +70 1520 1 +126 1520 1 +481 1520 1 +76 1521 1 +235 1521 1 +500 1521 1 +95 1522 1 +158 1522 1 +420 1522 1 +309 1523 1 +354 1523 1 +472 1523 1 +147 1524 1 +150 1524 1 +509 1524 1 +34 1525 1 +53 1525 1 +394 1525 1 +308 1526 1 +331 1526 1 +450 1526 1 +19 1527 1 +68 1527 1 +255 1527 1 +237 1528 1 +280 1528 1 +472 1528 1 +21 1529 1 +51 1529 1 +373 1529 1 +217 1530 1 +219 1530 1 +365 1530 1 +115 1531 1 +432 1531 1 +488 1531 1 +49 1532 1 +90 1532 1 +305 1532 1 +177 1533 1 +236 1533 1 +496 1533 1 +201 1534 1 +213 1534 1 +418 1534 1 +88 1535 1 +137 1535 1 +193 1535 1 +149 1536 1 +289 1536 1 +368 1536 1 +163 1537 1 +256 1537 1 +305 1537 1 +5 1538 1 +366 1538 1 +508 1538 1 +325 1539 1 +469 1539 1 +495 1539 1 +455 1540 1 +484 1540 1 +494 1540 1 +96 1541 1 +125 1541 1 +199 1541 1 +52 1542 1 +289 1542 1 +420 1542 1 +77 1543 1 +454 1543 1 +514 1543 1 +24 1544 1 +49 1544 1 +450 1544 1 +152 1545 1 +155 1545 1 +201 1545 1 +130 1546 1 +392 1546 1 +496 1546 1 +207 1547 1 +221 1547 1 +238 1547 1 +67 1548 1 +181 1548 1 +264 1548 1 +220 1549 1 +238 1549 1 +411 1549 1 +36 1550 1 +137 1550 1 +358 1550 1 +18 1551 1 +85 1551 1 +229 1551 1 +48 1552 1 +222 1552 1 +287 1552 1 +88 1553 1 +105 1553 1 +493 1553 1 +40 1554 1 +228 1554 1 +346 1554 1 +148 1555 1 +351 1555 1 +409 1555 1 +179 1556 1 +380 1556 1 +489 1556 1 +6 1557 1 +22 1557 1 +102 1557 1 +155 1558 1 +379 1558 1 +480 1558 1 +19 1559 1 +322 1559 1 +413 1559 1 +138 1560 1 +409 1560 1 +435 1560 1 +74 1561 1 +215 1561 1 +290 1561 1 +39 1562 1 +234 1562 1 +317 1562 1 +51 1563 1 +174 1563 1 +303 1563 1 +198 1564 1 +275 1564 1 +348 1564 1 +141 1565 1 +356 1565 1 +376 1565 1 +142 1566 1 +182 1566 1 +314 1566 1 +106 1567 1 +212 1567 1 +422 1567 1 +103 1568 1 +272 1568 1 +297 1568 1 +67 1569 1 +203 1569 1 +343 1569 1 +111 1570 1 +194 1570 1 +250 1570 1 +107 1571 1 +426 1571 1 +513 1571 1 +186 1572 1 +215 1572 1 +466 1572 1 +68 1573 1 +279 1573 1 +290 1573 1 +37 1574 1 +234 1574 1 +289 1574 1 +166 1575 1 +279 1575 1 +431 1575 1 +28 1576 1 +388 1576 1 +503 1576 1 +94 1577 1 +164 1577 1 +451 1577 1 +289 1578 1 +318 1578 1 +516 1578 1 +15 1579 1 +219 1579 1 +328 1579 1 +126 1580 1 +205 1580 1 +305 1580 1 +121 1581 1 +152 1581 1 +427 1581 1 +43 1582 1 +74 1582 1 +361 1582 1 +108 1583 1 +304 1583 1 +307 1583 1 +117 1584 1 +242 1584 1 +469 1584 1 +128 1585 1 +136 1585 1 +341 1585 1 +406 1586 1 +440 1586 1 +476 1586 1 +71 1587 1 +304 1587 1 +371 1587 1 +333 1588 1 +466 1588 1 +489 1588 1 +39 1589 1 +238 1589 1 +328 1589 1 +38 1590 1 +347 1590 1 +355 1590 1 +69 1591 1 +201 1591 1 +310 1591 1 +313 1592 1 +373 1592 1 +437 1592 1 +267 1593 1 +275 1593 1 +515 1593 1 +17 1594 1 +325 1594 1 +402 1594 1 +249 1595 1 +364 1595 1 +386 1595 1 +40 1596 1 +362 1596 1 +403 1596 1 +351 1597 1 +393 1597 1 +412 1597 1 +40 1598 1 +103 1598 1 +357 1598 1 +202 1599 1 +394 1599 1 +440 1599 1 +138 1600 1 +365 1600 1 +486 1600 1 +262 1601 1 +359 1601 1 +448 1601 1 +105 1602 1 +338 1602 1 +399 1602 1 +324 1603 1 +332 1603 1 +337 1603 1 +75 1604 1 +322 1604 1 +514 1604 1 +267 1605 1 +369 1605 1 +426 1605 1 +123 1606 1 +270 1606 1 +478 1606 1 +141 1607 1 +216 1607 1 +506 1607 1 +156 1608 1 +363 1608 1 +462 1608 1 +78 1609 1 +135 1609 1 +360 1609 1 +112 1610 1 +353 1610 1 +466 1610 1 +408 1611 1 +460 1611 1 +496 1611 1 +97 1612 1 +157 1612 1 +279 1612 1 +173 1613 1 +282 1613 1 +397 1613 1 +91 1614 1 +402 1614 1 +479 1614 1 +99 1615 1 +414 1615 1 +428 1615 1 +239 1616 1 +393 1616 1 +505 1616 1 +25 1617 1 +196 1617 1 +421 1617 1 +376 1618 1 +403 1618 1 +461 1618 1 +25 1619 1 +178 1619 1 +257 1619 1 +254 1620 1 +294 1620 1 +437 1620 1 +185 1621 1 +276 1621 1 +418 1621 1 +157 1622 1 +193 1622 1 +315 1622 1 +15 1623 1 +282 1623 1 +440 1623 1 +61 1624 1 +217 1624 1 +498 1624 1 +71 1625 1 +86 1625 1 +337 1625 1 +113 1626 1 +234 1626 1 +387 1626 1 +237 1627 1 +351 1627 1 +490 1627 1 +237 1628 1 +433 1628 1 +437 1628 1 +48 1629 1 +337 1629 1 +466 1629 1 +29 1630 1 +64 1630 1 +220 1630 1 +89 1631 1 +236 1631 1 +500 1631 1 +1 1632 1 +184 1632 1 +479 1632 1 +79 1633 1 +423 1633 1 +470 1633 1 +41 1634 1 +64 1634 1 +218 1634 1 +3 1635 1 +362 1635 1 +380 1635 1 +24 1636 1 +241 1636 1 +431 1636 1 +13 1637 1 +210 1637 1 +243 1637 1 +187 1638 1 +247 1638 1 +396 1638 1 +96 1639 1 +483 1639 1 +492 1639 1 +52 1640 1 +298 1640 1 +443 1640 1 +30 1641 1 +122 1641 1 +507 1641 1 +137 1642 1 +191 1642 1 +373 1642 1 +70 1643 1 +243 1643 1 +477 1643 1 +82 1644 1 +245 1644 1 +395 1644 1 +1 1645 1 +46 1645 1 +188 1645 1 +47 1646 1 +458 1646 1 +496 1646 1 +34 1647 1 +278 1647 1 +366 1647 1 +444 1648 1 +447 1648 1 +457 1648 1 +146 1649 1 +311 1649 1 +422 1649 1 +63 1650 1 +326 1650 1 +336 1650 1 +47 1651 1 +360 1651 1 +376 1651 1 +59 1652 1 +71 1652 1 +450 1652 1 +154 1653 1 +224 1653 1 +391 1653 1 +115 1654 1 +354 1654 1 +494 1654 1 +129 1655 1 +148 1655 1 +245 1655 1 +298 1656 1 +360 1656 1 +384 1656 1 +61 1657 1 +74 1657 1 +77 1657 1 +3 1658 1 +6 1658 1 +44 1658 1 +64 1659 1 +215 1659 1 +478 1659 1 +85 1660 1 +290 1660 1 +438 1660 1 +75 1661 1 +374 1661 1 +454 1661 1 +244 1662 1 +313 1662 1 +407 1662 1 +12 1663 1 +200 1663 1 +285 1663 1 +47 1664 1 +185 1664 1 +508 1664 1 +101 1665 1 +116 1665 1 +198 1665 1 +103 1666 1 +133 1666 1 +457 1666 1 +7 1667 1 +28 1667 1 +261 1667 1 +169 1668 1 +224 1668 1 +322 1668 1 +125 1669 1 +467 1669 1 +492 1669 1 +213 1670 1 +357 1670 1 +482 1670 1 +271 1671 1 +291 1671 1 +338 1671 1 +378 1672 1 +473 1672 1 +512 1672 1 +271 1673 1 +379 1673 1 +405 1673 1 +100 1674 1 +388 1674 1 +420 1674 1 +126 1675 1 +188 1675 1 +312 1675 1 +134 1676 1 +246 1676 1 +464 1676 1 +131 1677 1 +340 1677 1 +416 1677 1 +31 1678 1 +67 1678 1 +80 1678 1 +32 1679 1 +240 1679 1 +412 1679 1 +16 1680 1 +144 1680 1 +249 1680 1 +310 1681 1 +475 1681 1 +501 1681 1 +222 1682 1 +314 1682 1 +412 1682 1 +95 1683 1 +193 1683 1 +452 1683 1 +12 1684 1 +179 1684 1 +505 1684 1 +154 1685 1 +215 1685 1 +426 1685 1 +89 1686 1 +150 1686 1 +379 1686 1 +391 1687 1 +423 1687 1 +451 1687 1 +205 1688 1 +360 1688 1 +479 1688 1 +8 1689 1 +192 1689 1 +387 1689 1 +27 1690 1 +102 1690 1 +137 1690 1 +1 1691 1 +159 1691 1 +340 1691 1 +85 1692 1 +127 1692 1 +507 1692 1 +192 1693 1 +204 1693 1 +483 1693 1 +85 1694 1 +154 1694 1 +459 1694 1 +117 1695 1 +168 1695 1 +203 1695 1 +140 1696 1 +423 1696 1 +453 1696 1 +127 1697 1 +373 1697 1 +420 1697 1 +132 1698 1 +172 1698 1 +358 1698 1 +35 1699 1 +48 1699 1 +84 1699 1 +31 1700 1 +140 1700 1 +499 1700 1 +12 1701 1 +327 1701 1 +503 1701 1 +263 1702 1 +292 1702 1 +408 1702 1 +121 1703 1 +358 1703 1 +443 1703 1 +6 1704 1 +221 1704 1 +350 1704 1 +81 1705 1 +426 1705 1 +515 1705 1 +65 1706 1 +154 1706 1 +200 1706 1 +71 1707 1 +101 1707 1 +295 1707 1 +78 1708 1 +331 1708 1 +376 1708 1 +88 1709 1 +337 1709 1 +442 1709 1 +140 1710 1 +235 1710 1 +369 1710 1 +85 1711 1 +102 1711 1 +423 1711 1 +227 1712 1 +251 1712 1 +346 1712 1 +347 1713 1 +409 1713 1 +420 1713 1 +68 1714 1 +238 1714 1 +445 1714 1 +50 1715 1 +283 1715 1 +456 1715 1 +7 1716 1 +151 1716 1 +465 1716 1 +44 1717 1 +307 1717 1 +337 1717 1 +215 1718 1 +278 1718 1 +475 1718 1 +128 1719 1 +357 1719 1 +438 1719 1 +26 1720 1 +247 1720 1 +258 1720 1 +2 1721 1 +484 1721 1 +506 1721 1 +96 1722 1 +229 1722 1 +377 1722 1 +55 1723 1 +152 1723 1 +364 1723 1 +66 1724 1 +69 1724 1 +185 1724 1 +54 1725 1 +311 1725 1 +321 1725 1 +22 1726 1 +241 1726 1 +305 1726 1 +161 1727 1 +225 1727 1 +282 1727 1 +258 1728 1 +388 1728 1 +509 1728 1 +7 1729 1 +230 1729 1 +301 1729 1 +13 1730 1 +140 1730 1 +321 1730 1 +124 1731 1 +146 1731 1 +398 1731 1 +101 1732 1 +370 1732 1 +456 1732 1 +265 1733 1 +429 1733 1 +511 1733 1 +21 1734 1 +26 1734 1 +465 1734 1 +83 1735 1 +134 1735 1 +281 1735 1 +233 1736 1 +466 1736 1 +516 1736 1 +203 1737 1 +240 1737 1 +450 1737 1 +274 1738 1 +372 1738 1 +435 1738 1 +59 1739 1 +197 1739 1 +286 1739 1 +354 1740 1 +389 1740 1 +416 1740 1 +99 1741 1 +145 1741 1 +475 1741 1 +59 1742 1 +136 1742 1 +254 1742 1 +139 1743 1 +176 1743 1 +393 1743 1 +13 1744 1 +187 1744 1 +469 1744 1 +377 1745 1 +400 1745 1 +414 1745 1 +107 1746 1 +264 1746 1 +429 1746 1 +102 1747 1 +221 1747 1 +460 1747 1 +23 1748 1 +366 1748 1 +389 1748 1 +184 1749 1 +446 1749 1 +478 1749 1 +32 1750 1 +311 1750 1 +492 1750 1 +115 1751 1 +364 1751 1 +503 1751 1 +61 1752 1 +186 1752 1 +453 1752 1 +169 1753 1 +404 1753 1 +444 1753 1 +320 1754 1 +363 1754 1 +393 1754 1 +27 1755 1 +101 1755 1 +467 1755 1 +171 1756 1 +243 1756 1 +294 1756 1 +293 1757 1 +400 1757 1 +420 1757 1 +57 1758 1 +120 1758 1 +157 1758 1 +62 1759 1 +146 1759 1 +279 1759 1 +46 1760 1 +389 1760 1 +513 1760 1 +58 1761 1 +203 1761 1 +497 1761 1 +147 1762 1 +190 1762 1 +204 1762 1 +139 1763 1 +278 1763 1 +444 1763 1 +235 1764 1 +300 1764 1 +514 1764 1 +52 1765 1 +260 1765 1 +348 1765 1 +46 1766 1 +196 1766 1 +459 1766 1 +375 1767 1 +430 1767 1 +454 1767 1 +46 1768 1 +106 1768 1 +270 1768 1 +218 1769 1 +260 1769 1 +413 1769 1 +319 1770 1 +367 1770 1 +440 1770 1 +368 1771 1 +436 1771 1 +494 1771 1 +61 1772 1 +222 1772 1 +434 1772 1 +29 1773 1 +359 1773 1 +465 1773 1 +174 1774 1 +433 1774 1 +505 1774 1 +172 1775 1 +417 1775 1 +429 1775 1 +83 1776 1 +184 1776 1 +384 1776 1 +325 1777 1 +371 1777 1 +514 1777 1 +29 1778 1 +301 1778 1 +466 1778 1 +200 1779 1 +275 1779 1 +486 1779 1 +198 1780 1 +336 1780 1 +475 1780 1 +18 1781 1 +111 1781 1 +510 1781 1 +303 1782 1 +428 1782 1 +436 1782 1 +114 1783 1 +129 1783 1 +437 1783 1 +173 1784 1 +304 1784 1 +434 1784 1 +213 1785 1 +303 1785 1 +457 1785 1 +35 1786 1 +73 1786 1 +516 1786 1 +102 1787 1 +224 1787 1 +454 1787 1 +20 1788 1 +449 1788 1 +473 1788 1 +35 1789 1 +175 1789 1 +332 1789 1 +211 1790 1 +255 1790 1 +433 1790 1 +46 1791 1 +446 1791 1 +479 1791 1 +180 1792 1 +326 1792 1 +499 1792 1 +99 1793 1 +123 1793 1 +405 1793 1 +301 1794 1 +315 1794 1 +482 1794 1 +250 1795 1 +315 1795 1 +497 1795 1 +208 1796 1 +223 1796 1 +503 1796 1 +178 1797 1 +327 1797 1 +411 1797 1 +93 1798 1 +161 1798 1 +351 1798 1 +30 1799 1 +194 1799 1 +199 1799 1 +76 1800 1 +97 1800 1 +380 1800 1 +52 1801 1 +201 1801 1 +216 1801 1 +165 1802 1 +309 1802 1 +420 1802 1 +159 1803 1 +383 1803 1 +387 1803 1 +372 1804 1 +407 1804 1 +426 1804 1 +225 1805 1 +302 1805 1 +450 1805 1 +278 1806 1 +326 1806 1 +404 1806 1 +138 1807 1 +209 1807 1 +370 1807 1 +136 1808 1 +324 1808 1 +447 1808 1 +145 1809 1 +198 1809 1 +386 1809 1 +231 1810 1 +356 1810 1 +452 1810 1 +79 1811 1 +107 1811 1 +135 1811 1 +44 1812 1 +88 1812 1 +253 1812 1 +137 1813 1 +189 1813 1 +482 1813 1 +50 1814 1 +276 1814 1 +416 1814 1 +55 1815 1 +247 1815 1 +276 1815 1 +119 1816 1 +144 1816 1 +171 1816 1 +125 1817 1 +339 1817 1 +419 1817 1 +39 1818 1 +320 1818 1 +420 1818 1 +138 1819 1 +221 1819 1 +288 1819 1 +101 1820 1 +169 1820 1 +241 1820 1 +25 1821 1 +140 1821 1 +474 1821 1 +166 1822 1 +226 1822 1 +391 1822 1 +23 1823 1 +118 1823 1 +368 1823 1 +192 1824 1 +379 1824 1 +488 1824 1 +18 1825 1 +333 1825 1 +365 1825 1 +39 1826 1 +69 1826 1 +400 1826 1 +178 1827 1 +300 1827 1 +363 1827 1 +116 1828 1 +262 1828 1 +354 1828 1 +28 1829 1 +218 1829 1 +274 1829 1 +178 1830 1 +265 1830 1 +415 1830 1 +59 1831 1 +257 1831 1 +345 1831 1 +188 1832 1 +251 1832 1 +376 1832 1 +198 1833 1 +310 1833 1 +467 1833 1 +16 1834 1 +27 1834 1 +138 1834 1 +96 1835 1 +265 1835 1 +479 1835 1 +46 1836 1 +227 1836 1 +295 1836 1 +186 1837 1 +369 1837 1 +391 1837 1 +108 1838 1 +220 1838 1 +382 1838 1 +59 1839 1 +146 1839 1 +483 1839 1 +255 1840 1 +412 1840 1 +444 1840 1 +199 1841 1 +265 1841 1 +446 1841 1 +258 1842 1 +272 1842 1 +390 1842 1 +252 1843 1 +286 1843 1 +304 1843 1 +88 1844 1 +286 1844 1 +510 1844 1 +118 1845 1 +229 1845 1 +507 1845 1 +134 1846 1 +283 1846 1 +385 1846 1 +383 1847 1 +395 1847 1 +452 1847 1 +150 1848 1 +209 1848 1 +216 1848 1 +5 1849 1 +372 1849 1 +457 1849 1 +139 1850 1 +290 1850 1 +472 1850 1 +239 1851 1 +488 1851 1 +498 1851 1 +228 1852 1 +293 1852 1 +438 1852 1 +38 1853 1 +184 1853 1 +408 1853 1 +227 1854 1 +360 1854 1 +388 1854 1 +263 1855 1 +342 1855 1 +368 1855 1 +43 1856 1 +194 1856 1 +498 1856 1 +67 1857 1 +132 1857 1 +464 1857 1 +175 1858 1 +313 1858 1 +462 1858 1 +97 1859 1 +290 1859 1 +466 1859 1 +188 1860 1 +448 1860 1 +508 1860 1 +63 1861 1 +385 1861 1 +515 1861 1 +147 1862 1 +162 1862 1 +321 1862 1 +189 1863 1 +232 1863 1 +375 1863 1 +17 1864 1 +31 1864 1 +337 1864 1 +154 1865 1 +270 1865 1 +448 1865 1 +62 1866 1 +271 1866 1 +273 1866 1 +370 1867 1 +383 1867 1 +455 1867 1 +219 1868 1 +318 1868 1 +435 1868 1 +1 1869 1 +242 1869 1 +380 1869 1 +198 1870 1 +251 1870 1 +354 1870 1 +22 1871 1 +157 1871 1 +254 1871 1 +56 1872 1 +79 1872 1 +242 1872 1 +90 1873 1 +119 1873 1 +324 1873 1 +318 1874 1 +421 1874 1 +489 1874 1 +15 1875 1 +401 1875 1 +477 1875 1 +20 1876 1 +178 1876 1 +245 1876 1 +171 1877 1 +231 1877 1 +427 1877 1 +45 1878 1 +152 1878 1 +195 1878 1 +100 1879 1 +207 1879 1 +508 1879 1 +30 1880 1 +55 1880 1 +187 1880 1 +126 1881 1 +163 1881 1 +210 1881 1 +131 1882 1 +274 1882 1 +328 1882 1 +234 1883 1 +313 1883 1 +498 1883 1 +11 1884 1 +125 1884 1 +145 1884 1 +207 1885 1 +251 1885 1 +485 1885 1 +254 1886 1 +256 1886 1 +304 1886 1 +299 1887 1 +468 1887 1 +493 1887 1 +349 1888 1 +385 1888 1 +392 1888 1 +120 1889 1 +329 1889 1 +507 1889 1 +196 1890 1 +227 1890 1 +324 1890 1 +21 1891 1 +272 1891 1 +400 1891 1 +26 1892 1 +317 1892 1 +419 1892 1 +170 1893 1 +196 1893 1 +430 1893 1 +114 1894 1 +427 1894 1 +439 1894 1 +77 1895 1 +466 1895 1 +513 1895 1 +8 1896 1 +96 1896 1 +432 1896 1 +57 1897 1 +216 1897 1 +417 1897 1 +190 1898 1 +449 1898 1 +496 1898 1 +11 1899 1 +14 1899 1 +364 1899 1 +214 1900 1 +441 1900 1 +474 1900 1 +212 1901 1 +333 1901 1 +511 1901 1 +345 1902 1 +484 1902 1 +493 1902 1 +179 1903 1 +363 1903 1 +435 1903 1 +225 1904 1 +383 1904 1 +487 1904 1 +64 1905 1 +303 1905 1 +366 1905 1 +114 1906 1 +155 1906 1 +364 1906 1 +80 1907 1 +172 1907 1 +455 1907 1 +185 1908 1 +188 1908 1 +384 1908 1 +66 1909 1 +348 1909 1 +359 1909 1 +138 1910 1 +169 1910 1 +195 1910 1 +149 1911 1 +256 1911 1 +329 1911 1 +43 1912 1 +199 1912 1 +263 1912 1 +190 1913 1 +193 1913 1 +349 1913 1 +127 1914 1 +188 1914 1 +248 1914 1 +3 1915 1 +455 1915 1 +486 1915 1 +3 1916 1 +86 1916 1 +371 1916 1 +153 1917 1 +161 1917 1 +166 1917 1 +222 1918 1 +235 1918 1 +257 1918 1 +210 1919 1 +247 1919 1 +471 1919 1 +11 1920 1 +288 1920 1 +339 1920 1 +56 1921 1 +135 1921 1 +380 1921 1 +104 1922 1 +344 1922 1 +357 1922 1 +53 1923 1 +427 1923 1 +437 1923 1 +153 1924 1 +381 1924 1 +441 1924 1 +130 1925 1 +148 1925 1 +191 1925 1 +56 1926 1 +261 1926 1 +443 1926 1 +83 1927 1 +128 1927 1 +268 1927 1 +71 1928 1 +193 1928 1 +197 1928 1 +274 1929 1 +287 1929 1 +444 1929 1 +95 1930 1 +221 1930 1 +306 1930 1 +74 1931 1 +347 1931 1 +363 1931 1 +121 1932 1 +155 1932 1 +160 1932 1 +106 1933 1 +172 1933 1 +346 1933 1 +173 1934 1 +204 1934 1 +345 1934 1 +16 1935 1 +334 1935 1 +376 1935 1 +114 1936 1 +255 1936 1 +401 1936 1 +270 1937 1 +380 1937 1 +479 1937 1 +33 1938 1 +189 1938 1 +195 1938 1 +53 1939 1 +241 1939 1 +243 1939 1 +267 1940 1 +277 1940 1 +514 1940 1 +49 1941 1 +226 1941 1 +481 1941 1 +332 1942 1 +448 1942 1 +489 1942 1 +306 1943 1 +413 1943 1 +445 1943 1 +68 1944 1 +81 1944 1 +432 1944 1 +35 1945 1 +441 1945 1 +451 1945 1 +28 1946 1 +223 1946 1 +460 1946 1 +32 1947 1 +162 1947 1 +252 1947 1 +213 1948 1 +429 1948 1 +443 1948 1 +24 1949 1 +292 1949 1 +332 1949 1 +113 1950 1 +205 1950 1 +283 1950 1 +40 1951 1 +146 1951 1 +416 1951 1 +18 1952 1 +439 1952 1 +502 1952 1 +9 1953 1 +110 1953 1 +140 1953 1 +89 1954 1 +114 1954 1 +164 1954 1 +294 1955 1 +304 1955 1 +415 1955 1 +250 1956 1 +261 1956 1 +359 1956 1 +256 1957 1 +378 1957 1 +470 1957 1 +70 1958 1 +88 1958 1 +90 1958 1 +208 1959 1 +278 1959 1 +411 1959 1 +291 1960 1 +386 1960 1 +425 1960 1 +91 1961 1 +123 1961 1 +422 1961 1 +82 1962 1 +226 1962 1 +352 1962 1 +314 1963 1 +329 1963 1 +344 1963 1 +39 1964 1 +165 1964 1 +501 1964 1 +7 1965 1 +83 1965 1 +386 1965 1 +181 1966 1 +295 1966 1 +335 1966 1 +78 1967 1 +213 1967 1 +458 1967 1 +13 1968 1 +408 1968 1 +449 1968 1 +301 1969 1 +355 1969 1 +478 1969 1 +405 1970 1 +414 1970 1 +480 1970 1 +112 1971 1 +336 1971 1 +477 1971 1 +316 1972 1 +440 1972 1 +487 1972 1 +156 1973 1 +366 1973 1 +413 1973 1 +393 1974 1 +409 1974 1 +444 1974 1 +12 1975 1 +142 1975 1 +244 1975 1 +110 1976 1 +153 1976 1 +157 1976 1 +48 1977 1 +168 1977 1 +451 1977 1 +73 1978 1 +128 1978 1 +423 1978 1 +166 1979 1 +470 1979 1 +480 1979 1 +39 1980 1 +266 1980 1 +297 1980 1 +17 1981 1 +82 1981 1 +284 1981 1 +132 1982 1 +280 1982 1 +495 1982 1 +204 1983 1 +428 1983 1 +431 1983 1 +104 1984 1 +250 1984 1 +384 1984 1 +63 1985 1 +360 1985 1 +418 1985 1 +62 1986 1 +238 1986 1 +363 1986 1 +1 1987 1 +99 1987 1 +325 1987 1 +45 1988 1 +53 1988 1 +245 1988 1 +393 1989 1 +424 1989 1 +447 1989 1 +5 1990 1 +176 1990 1 +313 1990 1 +115 1991 1 +285 1991 1 +485 1991 1 +47 1992 1 +263 1992 1 +436 1992 1 +18 1993 1 +212 1993 1 +391 1993 1 +248 1994 1 +268 1994 1 +357 1994 1 +16 1995 1 +316 1995 1 +512 1995 1 +272 1996 1 +377 1996 1 +490 1996 1 +75 1997 1 +335 1997 1 +487 1997 1 +317 1998 1 +387 1998 1 +417 1998 1 +84 1999 1 +168 1999 1 +512 1999 1 +70 2000 1 +144 2000 1 +324 2000 1 +342 2001 1 +428 2001 1 +496 2001 1 +207 2002 1 +326 2002 1 +366 2002 1 +14 2003 1 +132 2003 1 +152 2003 1 +191 2004 1 +232 2004 1 +452 2004 1 +77 2005 1 +252 2005 1 +343 2005 1 +154 2006 1 +300 2006 1 +361 2006 1 +12 2007 1 +51 2007 1 +389 2007 1 +107 2008 1 +146 2008 1 +254 2008 1 +230 2009 1 +308 2009 1 +446 2009 1 +132 2010 1 +371 2010 1 +471 2010 1 +280 2011 1 +486 2011 1 +502 2011 1 +42 2012 1 +279 2012 1 +399 2012 1 +23 2013 1 +275 2013 1 +485 2013 1 +147 2014 1 +370 2014 1 +395 2014 1 +149 2015 1 +223 2015 1 +345 2015 1 +17 2016 1 +33 2016 1 +474 2016 1 +18 2017 1 +304 2017 1 +337 2017 1 +8 2018 1 +296 2018 1 +481 2018 1 +174 2019 1 +217 2019 1 +249 2019 1 +73 2020 1 +442 2020 1 +510 2020 1 +261 2021 1 +360 2021 1 +458 2021 1 +197 2022 1 +280 2022 1 +514 2022 1 +72 2023 1 +75 2023 1 +90 2023 1 +4 2024 1 +354 2024 1 +362 2024 1 +15 2025 1 +182 2025 1 +463 2025 1 +34 2026 1 +139 2026 1 +347 2026 1 +163 2027 1 +397 2027 1 +477 2027 1 +159 2028 1 +236 2028 1 +257 2028 1 +136 2029 1 +442 2029 1 +489 2029 1 +12 2030 1 +361 2030 1 +405 2030 1 +36 2031 1 +45 2031 1 +143 2031 1 +196 2032 1 +233 2032 1 +259 2032 1 +3 2033 1 +193 2033 1 +286 2033 1 +40 2034 1 +479 2034 1 +495 2034 1 +167 2035 1 +206 2035 1 +382 2035 1 +71 2036 1 +153 2036 1 +224 2036 1 +101 2037 1 +121 2037 1 +177 2037 1 +111 2038 1 +299 2038 1 +446 2038 1 +100 2039 1 +201 2039 1 +260 2039 1 +237 2040 1 +255 2040 1 +427 2040 1 +300 2041 1 +426 2041 1 +438 2041 1 +32 2042 1 +318 2042 1 +434 2042 1 +76 2043 1 +286 2043 1 +511 2043 1 +9 2044 1 +54 2044 1 +187 2044 1 +14 2045 1 +143 2045 1 +383 2045 1 +137 2046 1 +302 2046 1 +423 2046 1 +6 2047 1 +57 2047 1 +193 2047 1 +53 2048 1 +148 2048 1 +430 2048 1 +202 2049 1 +320 2049 1 +427 2049 1 +71 2050 1 +231 2050 1 +447 2050 1 +52 2051 1 +218 2051 1 +435 2051 1 +148 2052 1 +377 2052 1 +487 2052 1 +219 2053 1 +498 2053 1 +502 2053 1 +17 2054 1 +206 2054 1 +338 2054 1 +299 2055 1 +359 2055 1 +407 2055 1 +41 2056 1 +238 2056 1 +323 2056 1 +108 2057 1 +235 2057 1 +407 2057 1 +48 2058 1 +379 2058 1 +387 2058 1 +143 2059 1 +160 2059 1 +166 2059 1 +65 2060 1 +391 2060 1 +512 2060 1 +316 2061 1 +381 2061 1 +473 2061 1 +133 2062 1 +261 2062 1 +310 2062 1 +142 2063 1 +297 2063 1 +457 2063 1 +92 2064 1 +277 2064 1 +490 2064 1 +1 2065 1 +2 2065 1 +2 2066 1 +3 2066 1 +3 2067 1 +4 2067 1 +4 2068 1 +5 2068 1 +5 2069 1 +6 2069 1 +6 2070 1 +7 2070 1 +7 2071 1 +8 2071 1 +8 2072 1 +9 2072 1 +9 2073 1 +10 2073 1 +10 2074 1 +11 2074 1 +11 2075 1 +12 2075 1 +12 2076 1 +13 2076 1 +13 2077 1 +14 2077 1 +14 2078 1 +15 2078 1 +15 2079 1 +16 2079 1 +16 2080 1 +17 2080 1 +17 2081 1 +18 2081 1 +18 2082 1 +19 2082 1 +19 2083 1 +20 2083 1 +20 2084 1 +21 2084 1 +21 2085 1 +22 2085 1 +22 2086 1 +23 2086 1 +23 2087 1 +24 2087 1 +24 2088 1 +25 2088 1 +25 2089 1 +26 2089 1 +26 2090 1 +27 2090 1 +27 2091 1 +28 2091 1 +28 2092 1 +29 2092 1 +29 2093 1 +30 2093 1 +30 2094 1 +31 2094 1 +31 2095 1 +32 2095 1 +32 2096 1 +33 2096 1 +33 2097 1 +34 2097 1 +34 2098 1 +35 2098 1 +35 2099 1 +36 2099 1 +36 2100 1 +37 2100 1 +37 2101 1 +38 2101 1 +38 2102 1 +39 2102 1 +39 2103 1 +40 2103 1 +40 2104 1 +41 2104 1 +41 2105 1 +42 2105 1 +42 2106 1 +43 2106 1 +43 2107 1 +44 2107 1 +44 2108 1 +45 2108 1 +45 2109 1 +46 2109 1 +46 2110 1 +47 2110 1 +47 2111 1 +48 2111 1 +48 2112 1 +49 2112 1 +49 2113 1 +50 2113 1 +50 2114 1 +51 2114 1 +51 2115 1 +52 2115 1 +52 2116 1 +53 2116 1 +53 2117 1 +54 2117 1 +54 2118 1 +55 2118 1 +55 2119 1 +56 2119 1 +56 2120 1 +57 2120 1 +57 2121 1 +58 2121 1 +58 2122 1 +59 2122 1 +59 2123 1 +60 2123 1 +60 2124 1 +61 2124 1 +61 2125 1 +62 2125 1 +62 2126 1 +63 2126 1 +63 2127 1 +64 2127 1 +64 2128 1 +65 2128 1 +65 2129 1 +66 2129 1 +66 2130 1 +67 2130 1 +67 2131 1 +68 2131 1 +68 2132 1 +69 2132 1 +69 2133 1 +70 2133 1 +70 2134 1 +71 2134 1 +71 2135 1 +72 2135 1 +72 2136 1 +73 2136 1 +73 2137 1 +74 2137 1 +74 2138 1 +75 2138 1 +75 2139 1 +76 2139 1 +76 2140 1 +77 2140 1 +77 2141 1 +78 2141 1 +78 2142 1 +79 2142 1 +79 2143 1 +80 2143 1 +80 2144 1 +81 2144 1 +81 2145 1 +82 2145 1 +82 2146 1 +83 2146 1 +83 2147 1 +84 2147 1 +84 2148 1 +85 2148 1 +85 2149 1 +86 2149 1 +86 2150 1 +87 2150 1 +87 2151 1 +88 2151 1 +88 2152 1 +89 2152 1 +89 2153 1 +90 2153 1 +90 2154 1 +91 2154 1 +91 2155 1 +92 2155 1 +92 2156 1 +93 2156 1 +93 2157 1 +94 2157 1 +94 2158 1 +95 2158 1 +95 2159 1 +96 2159 1 +96 2160 1 +97 2160 1 +97 2161 1 +98 2161 1 +98 2162 1 +99 2162 1 +99 2163 1 +100 2163 1 +100 2164 1 +101 2164 1 +101 2165 1 +102 2165 1 +102 2166 1 +103 2166 1 +103 2167 1 +104 2167 1 +104 2168 1 +105 2168 1 +105 2169 1 +106 2169 1 +106 2170 1 +107 2170 1 +107 2171 1 +108 2171 1 +108 2172 1 +109 2172 1 +109 2173 1 +110 2173 1 +110 2174 1 +111 2174 1 +111 2175 1 +112 2175 1 +112 2176 1 +113 2176 1 +113 2177 1 +114 2177 1 +114 2178 1 +115 2178 1 +115 2179 1 +116 2179 1 +116 2180 1 +117 2180 1 +117 2181 1 +118 2181 1 +118 2182 1 +119 2182 1 +119 2183 1 +120 2183 1 +120 2184 1 +121 2184 1 +121 2185 1 +122 2185 1 +122 2186 1 +123 2186 1 +123 2187 1 +124 2187 1 +124 2188 1 +125 2188 1 +125 2189 1 +126 2189 1 +126 2190 1 +127 2190 1 +127 2191 1 +128 2191 1 +128 2192 1 +129 2192 1 +129 2193 1 +130 2193 1 +130 2194 1 +131 2194 1 +131 2195 1 +132 2195 1 +132 2196 1 +133 2196 1 +133 2197 1 +134 2197 1 +134 2198 1 +135 2198 1 +135 2199 1 +136 2199 1 +136 2200 1 +137 2200 1 +137 2201 1 +138 2201 1 +138 2202 1 +139 2202 1 +139 2203 1 +140 2203 1 +140 2204 1 +141 2204 1 +141 2205 1 +142 2205 1 +142 2206 1 +143 2206 1 +143 2207 1 +144 2207 1 +144 2208 1 +145 2208 1 +145 2209 1 +146 2209 1 +146 2210 1 +147 2210 1 +147 2211 1 +148 2211 1 +148 2212 1 +149 2212 1 +149 2213 1 +150 2213 1 +150 2214 1 +151 2214 1 +151 2215 1 +152 2215 1 +152 2216 1 +153 2216 1 +153 2217 1 +154 2217 1 +154 2218 1 +155 2218 1 +155 2219 1 +156 2219 1 +156 2220 1 +157 2220 1 +157 2221 1 +158 2221 1 +158 2222 1 +159 2222 1 +159 2223 1 +160 2223 1 +160 2224 1 +161 2224 1 +161 2225 1 +162 2225 1 +162 2226 1 +163 2226 1 +163 2227 1 +164 2227 1 +164 2228 1 +165 2228 1 +165 2229 1 +166 2229 1 +166 2230 1 +167 2230 1 +167 2231 1 +168 2231 1 +168 2232 1 +169 2232 1 +169 2233 1 +170 2233 1 +170 2234 1 +171 2234 1 +171 2235 1 +172 2235 1 +172 2236 1 +173 2236 1 +173 2237 1 +174 2237 1 +174 2238 1 +175 2238 1 +175 2239 1 +176 2239 1 +176 2240 1 +177 2240 1 +177 2241 1 +178 2241 1 +178 2242 1 +179 2242 1 +179 2243 1 +180 2243 1 +180 2244 1 +181 2244 1 +181 2245 1 +182 2245 1 +182 2246 1 +183 2246 1 +183 2247 1 +184 2247 1 +184 2248 1 +185 2248 1 +185 2249 1 +186 2249 1 +186 2250 1 +187 2250 1 +187 2251 1 +188 2251 1 +188 2252 1 +189 2252 1 +189 2253 1 +190 2253 1 +190 2254 1 +191 2254 1 +191 2255 1 +192 2255 1 +192 2256 1 +193 2256 1 +193 2257 1 +194 2257 1 +194 2258 1 +195 2258 1 +195 2259 1 +196 2259 1 +196 2260 1 +197 2260 1 +197 2261 1 +198 2261 1 +198 2262 1 +199 2262 1 +199 2263 1 +200 2263 1 +200 2264 1 +201 2264 1 +201 2265 1 +202 2265 1 +202 2266 1 +203 2266 1 +203 2267 1 +204 2267 1 +204 2268 1 +205 2268 1 +205 2269 1 +206 2269 1 +206 2270 1 +207 2270 1 +207 2271 1 +208 2271 1 +208 2272 1 +209 2272 1 +209 2273 1 +210 2273 1 +210 2274 1 +211 2274 1 +211 2275 1 +212 2275 1 +212 2276 1 +213 2276 1 +213 2277 1 +214 2277 1 +214 2278 1 +215 2278 1 +215 2279 1 +216 2279 1 +216 2280 1 +217 2280 1 +217 2281 1 +218 2281 1 +218 2282 1 +219 2282 1 +219 2283 1 +220 2283 1 +220 2284 1 +221 2284 1 +221 2285 1 +222 2285 1 +222 2286 1 +223 2286 1 +223 2287 1 +224 2287 1 +224 2288 1 +225 2288 1 +225 2289 1 +226 2289 1 +226 2290 1 +227 2290 1 +227 2291 1 +228 2291 1 +228 2292 1 +229 2292 1 +229 2293 1 +230 2293 1 +230 2294 1 +231 2294 1 +231 2295 1 +232 2295 1 +232 2296 1 +233 2296 1 +233 2297 1 +234 2297 1 +234 2298 1 +235 2298 1 +235 2299 1 +236 2299 1 +236 2300 1 +237 2300 1 +237 2301 1 +238 2301 1 +238 2302 1 +239 2302 1 +239 2303 1 +240 2303 1 +240 2304 1 +241 2304 1 +241 2305 1 +242 2305 1 +242 2306 1 +243 2306 1 +243 2307 1 +244 2307 1 +244 2308 1 +245 2308 1 +245 2309 1 +246 2309 1 +246 2310 1 +247 2310 1 +247 2311 1 +248 2311 1 +248 2312 1 +249 2312 1 +249 2313 1 +250 2313 1 +250 2314 1 +251 2314 1 +251 2315 1 +252 2315 1 +252 2316 1 +253 2316 1 +253 2317 1 +254 2317 1 +254 2318 1 +255 2318 1 +255 2319 1 +256 2319 1 +256 2320 1 +257 2320 1 +257 2321 1 +258 2321 1 +258 2322 1 +259 2322 1 +259 2323 1 +260 2323 1 +260 2324 1 +261 2324 1 +261 2325 1 +262 2325 1 +262 2326 1 +263 2326 1 +263 2327 1 +264 2327 1 +264 2328 1 +265 2328 1 +265 2329 1 +266 2329 1 +266 2330 1 +267 2330 1 +267 2331 1 +268 2331 1 +268 2332 1 +269 2332 1 +269 2333 1 +270 2333 1 +270 2334 1 +271 2334 1 +271 2335 1 +272 2335 1 +272 2336 1 +273 2336 1 +273 2337 1 +274 2337 1 +274 2338 1 +275 2338 1 +275 2339 1 +276 2339 1 +276 2340 1 +277 2340 1 +277 2341 1 +278 2341 1 +278 2342 1 +279 2342 1 +279 2343 1 +280 2343 1 +280 2344 1 +281 2344 1 +281 2345 1 +282 2345 1 +282 2346 1 +283 2346 1 +283 2347 1 +284 2347 1 +284 2348 1 +285 2348 1 +285 2349 1 +286 2349 1 +286 2350 1 +287 2350 1 +287 2351 1 +288 2351 1 +288 2352 1 +289 2352 1 +289 2353 1 +290 2353 1 +290 2354 1 +291 2354 1 +291 2355 1 +292 2355 1 +292 2356 1 +293 2356 1 +293 2357 1 +294 2357 1 +294 2358 1 +295 2358 1 +295 2359 1 +296 2359 1 +296 2360 1 +297 2360 1 +297 2361 1 +298 2361 1 +298 2362 1 +299 2362 1 +299 2363 1 +300 2363 1 +300 2364 1 +301 2364 1 +301 2365 1 +302 2365 1 +302 2366 1 +303 2366 1 +303 2367 1 +304 2367 1 +304 2368 1 +305 2368 1 +305 2369 1 +306 2369 1 +306 2370 1 +307 2370 1 +307 2371 1 +308 2371 1 +308 2372 1 +309 2372 1 +309 2373 1 +310 2373 1 +310 2374 1 +311 2374 1 +311 2375 1 +312 2375 1 +312 2376 1 +313 2376 1 +313 2377 1 +314 2377 1 +314 2378 1 +315 2378 1 +315 2379 1 +316 2379 1 +316 2380 1 +317 2380 1 +317 2381 1 +318 2381 1 +318 2382 1 +319 2382 1 +319 2383 1 +320 2383 1 +320 2384 1 +321 2384 1 +321 2385 1 +322 2385 1 +322 2386 1 +323 2386 1 +323 2387 1 +324 2387 1 +324 2388 1 +325 2388 1 +325 2389 1 +326 2389 1 +326 2390 1 +327 2390 1 +327 2391 1 +328 2391 1 +328 2392 1 +329 2392 1 +329 2393 1 +330 2393 1 +330 2394 1 +331 2394 1 +331 2395 1 +332 2395 1 +332 2396 1 +333 2396 1 +333 2397 1 +334 2397 1 +334 2398 1 +335 2398 1 +335 2399 1 +336 2399 1 +336 2400 1 +337 2400 1 +337 2401 1 +338 2401 1 +338 2402 1 +339 2402 1 +339 2403 1 +340 2403 1 +340 2404 1 +341 2404 1 +341 2405 1 +342 2405 1 +342 2406 1 +343 2406 1 +343 2407 1 +344 2407 1 +344 2408 1 +345 2408 1 +345 2409 1 +346 2409 1 +346 2410 1 +347 2410 1 +347 2411 1 +348 2411 1 +348 2412 1 +349 2412 1 +349 2413 1 +350 2413 1 +350 2414 1 +351 2414 1 +351 2415 1 +352 2415 1 +352 2416 1 +353 2416 1 +353 2417 1 +354 2417 1 +354 2418 1 +355 2418 1 +355 2419 1 +356 2419 1 +356 2420 1 +357 2420 1 +357 2421 1 +358 2421 1 +358 2422 1 +359 2422 1 +359 2423 1 +360 2423 1 +360 2424 1 +361 2424 1 +361 2425 1 +362 2425 1 +362 2426 1 +363 2426 1 +363 2427 1 +364 2427 1 +364 2428 1 +365 2428 1 +365 2429 1 +366 2429 1 +366 2430 1 +367 2430 1 +367 2431 1 +368 2431 1 +368 2432 1 +369 2432 1 +369 2433 1 +370 2433 1 +370 2434 1 +371 2434 1 +371 2435 1 +372 2435 1 +372 2436 1 +373 2436 1 +373 2437 1 +374 2437 1 +374 2438 1 +375 2438 1 +375 2439 1 +376 2439 1 +376 2440 1 +377 2440 1 +377 2441 1 +378 2441 1 +378 2442 1 +379 2442 1 +379 2443 1 +380 2443 1 +380 2444 1 +381 2444 1 +381 2445 1 +382 2445 1 +382 2446 1 +383 2446 1 +383 2447 1 +384 2447 1 +384 2448 1 +385 2448 1 +385 2449 1 +386 2449 1 +386 2450 1 +387 2450 1 +387 2451 1 +388 2451 1 +388 2452 1 +389 2452 1 +389 2453 1 +390 2453 1 +390 2454 1 +391 2454 1 +391 2455 1 +392 2455 1 +392 2456 1 +393 2456 1 +393 2457 1 +394 2457 1 +394 2458 1 +395 2458 1 +395 2459 1 +396 2459 1 +396 2460 1 +397 2460 1 +397 2461 1 +398 2461 1 +398 2462 1 +399 2462 1 +399 2463 1 +400 2463 1 +400 2464 1 +401 2464 1 +401 2465 1 +402 2465 1 +402 2466 1 +403 2466 1 +403 2467 1 +404 2467 1 +404 2468 1 +405 2468 1 +405 2469 1 +406 2469 1 +406 2470 1 +407 2470 1 +407 2471 1 +408 2471 1 +408 2472 1 +409 2472 1 +409 2473 1 +410 2473 1 +410 2474 1 +411 2474 1 +411 2475 1 +412 2475 1 +412 2476 1 +413 2476 1 +413 2477 1 +414 2477 1 +414 2478 1 +415 2478 1 +415 2479 1 +416 2479 1 +416 2480 1 +417 2480 1 +417 2481 1 +418 2481 1 +418 2482 1 +419 2482 1 +419 2483 1 +420 2483 1 +420 2484 1 +421 2484 1 +421 2485 1 +422 2485 1 +422 2486 1 +423 2486 1 +423 2487 1 +424 2487 1 +424 2488 1 +425 2488 1 +425 2489 1 +426 2489 1 +426 2490 1 +427 2490 1 +427 2491 1 +428 2491 1 +428 2492 1 +429 2492 1 +429 2493 1 +430 2493 1 +430 2494 1 +431 2494 1 +431 2495 1 +432 2495 1 +432 2496 1 +433 2496 1 +433 2497 1 +434 2497 1 +434 2498 1 +435 2498 1 +435 2499 1 +436 2499 1 +436 2500 1 +437 2500 1 +437 2501 1 +438 2501 1 +438 2502 1 +439 2502 1 +439 2503 1 +440 2503 1 +440 2504 1 +441 2504 1 +441 2505 1 +442 2505 1 +442 2506 1 +443 2506 1 +443 2507 1 +444 2507 1 +444 2508 1 +445 2508 1 +445 2509 1 +446 2509 1 +446 2510 1 +447 2510 1 +447 2511 1 +448 2511 1 +448 2512 1 +449 2512 1 +449 2513 1 +450 2513 1 +450 2514 1 +451 2514 1 +451 2515 1 +452 2515 1 +452 2516 1 +453 2516 1 +453 2517 1 +454 2517 1 +454 2518 1 +455 2518 1 +455 2519 1 +456 2519 1 +456 2520 1 +457 2520 1 +457 2521 1 +458 2521 1 +458 2522 1 +459 2522 1 +459 2523 1 +460 2523 1 +460 2524 1 +461 2524 1 +461 2525 1 +462 2525 1 +462 2526 1 +463 2526 1 +463 2527 1 +464 2527 1 +464 2528 1 +465 2528 1 +465 2529 1 +466 2529 1 +466 2530 1 +467 2530 1 +467 2531 1 +468 2531 1 +468 2532 1 +469 2532 1 +469 2533 1 +470 2533 1 +470 2534 1 +471 2534 1 +471 2535 1 +472 2535 1 +472 2536 1 +473 2536 1 +473 2537 1 +474 2537 1 +474 2538 1 +475 2538 1 +475 2539 1 +476 2539 1 +476 2540 1 +477 2540 1 +477 2541 1 +478 2541 1 +478 2542 1 +479 2542 1 +479 2543 1 +480 2543 1 +480 2544 1 +481 2544 1 +481 2545 1 +482 2545 1 +482 2546 1 +483 2546 1 +483 2547 1 +484 2547 1 +484 2548 1 +485 2548 1 +485 2549 1 +486 2549 1 +486 2550 1 +487 2550 1 +487 2551 1 +488 2551 1 +488 2552 1 +489 2552 1 +489 2553 1 +490 2553 1 +490 2554 1 +491 2554 1 +491 2555 1 +492 2555 1 +492 2556 1 +493 2556 1 +493 2557 1 +494 2557 1 +494 2558 1 +495 2558 1 +495 2559 1 +496 2559 1 +496 2560 1 +497 2560 1 +497 2561 1 +498 2561 1 +498 2562 1 +499 2562 1 +499 2563 1 +500 2563 1 +500 2564 1 +501 2564 1 +501 2565 1 +502 2565 1 +502 2566 1 +503 2566 1 +503 2567 1 +504 2567 1 +504 2568 1 +505 2568 1 +505 2569 1 +506 2569 1 +506 2570 1 +507 2570 1 +507 2571 1 +508 2571 1 +508 2572 1 +509 2572 1 +509 2573 1 +510 2573 1 +510 2574 1 +511 2574 1 +511 2575 1 +512 2575 1 +512 2576 1 +513 2576 1 +513 2577 1 +514 2577 1 +514 2578 1 +515 2578 1 +515 2579 1 +516 2579 1 +516 2580 1 + + diff --git a/codec2/branches/0.7/octave/HRA_112_112.txt b/codec2/branches/0.7/octave/HRA_112_112.txt new file mode 100644 index 00000000..e7746401 --- /dev/null +++ b/codec2/branches/0.7/octave/HRA_112_112.txt @@ -0,0 +1,119 @@ +# Created by Octave 3.8.1, Wed Mar 15 17:24:05 2017 ACDT +# name: HRA_112_112 +# type: matrix +# rows: 112 +# columns: 224 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + + diff --git a/codec2/branches/0.7/octave/HRA_112_56.txt b/codec2/branches/0.7/octave/HRA_112_56.txt new file mode 100644 index 00000000..1df20d8c --- /dev/null +++ b/codec2/branches/0.7/octave/HRA_112_56.txt @@ -0,0 +1,63 @@ +# Created by Octave 3.8.1, Wed Mar 15 17:59:13 2017 ACDT +# name: HRA_112_56 +# type: matrix +# rows: 56 +# columns: 168 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 + 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + + diff --git a/codec2/branches/0.7/octave/HRA_56_28.txt b/codec2/branches/0.7/octave/HRA_56_28.txt new file mode 100644 index 00000000..ae762484 --- /dev/null +++ b/codec2/branches/0.7/octave/HRA_56_28.txt @@ -0,0 +1,35 @@ +# Created by Octave 3.8.1, Wed Mar 15 18:20:20 2017 ACDT +# name: HRA_56_28 +# type: matrix +# rows: 28 +# columns: 84 + 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 + 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + + diff --git a/codec2/branches/0.7/octave/HRA_56_56.txt b/codec2/branches/0.7/octave/HRA_56_56.txt new file mode 100644 index 00000000..8a18f2d6 --- /dev/null +++ b/codec2/branches/0.7/octave/HRA_56_56.txt @@ -0,0 +1,63 @@ +# Created by Octave 3.8.1, Wed Mar 15 18:12:09 2017 ACDT +# name: HRA_56_56 +# type: matrix +# rows: 56 +# columns: 112 + 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 + 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 + 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 + + diff --git a/codec2/branches/0.7/octave/Mat2Hrows.m b/codec2/branches/0.7/octave/Mat2Hrows.m new file mode 100644 index 00000000..99db4f83 --- /dev/null +++ b/codec2/branches/0.7/octave/Mat2Hrows.m @@ -0,0 +1,26 @@ +function [Hrows Hcols] = Mat2Hrows(HRA); + +H = full(HRA); +[Nr Nc] = size(H); + +H= H(:,1:Nc-Nr); +[Nr Nc] = size(H); + + + +Max_colwt = max(sum(H)); +Max_rowwt = max(sum(H')); +Hcols = zeros(Nc, Max_colwt); +Hrows = zeros(Nr, Max_rowwt); + +for i = 1:Nr + nz = find(H(i,:)); + Hrows(i,1:length(nz)) = nz; +end + +H = H'; +for i = 1:Nc + nz = find(H(i,:)); + Hcols(i,1:length(nz)) = nz; +end + diff --git a/codec2/branches/0.7/octave/adc_plot_spec.m b/codec2/branches/0.7/octave/adc_plot_spec.m new file mode 100755 index 00000000..2bc38057 --- /dev/null +++ b/codec2/branches/0.7/octave/adc_plot_spec.m @@ -0,0 +1,51 @@ +#!/usr/bin/env octave +% Plot the spectrum and waveform coming off of the ADC + +% Author: Brady O'Brien 28 June 2016 + +% Copyright 2016 Brady O'Brien +% +% All rights reserved. +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License version 2, as +% published by the Free Software Foundation. This program is +% distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +% License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with this program; if not, see . + + +%adc_file_name = '/home/baobrien/workspace/freetel-code/codec2-dev/stm32/adc_samp' +adc_file_name = '/dev/ttyACM0' +%adc_file_name = 'infifo'; +fs = 96000 +sampsize = 19200 +%graphics_toolkit('gnuplot') + +fin = fopen(adc_file_name,'r') +first = 1 +cont = 0 +sampinc = (1/sampsize)*fs + +[samps cont] = fread(fin,sampsize,'short'); +y = (1:(sampsize/2)); +yp = (1:sampsize/2)*(fs/(sampsize/2)); +pltdat = plot(10*log10(abs(fft(samps)(y)))); +pltx = 10*log10(abs(fft(samps)(y))); +axis([0 fs 30 80]) +set (pltdat, "ydatasource", "pltx"); +set (pltdat, "xdatasource", "yp"); +%set (pltdat, "ydatasource", "y"); + +while(first || cont==sampsize) + first = 0; + %sleep(.001); + [samps cont] = fread(fin,sampsize,'short'); + pltx = 10*log10(abs(fft(samps)(y))); + refreshdata + refresh +endwhile diff --git a/codec2/branches/0.7/octave/adc_sfdr_ut.m b/codec2/branches/0.7/octave/adc_sfdr_ut.m new file mode 100644 index 00000000..06fcf307 --- /dev/null +++ b/codec2/branches/0.7/octave/adc_sfdr_ut.m @@ -0,0 +1,34 @@ +% adc_sfdr_ut.m +% David Rowe Aug 2015 +% +% Processes data collected from STM32F4 or SFDR testing of ADC + +s = load_raw("~/stlink/adc.raw"); +Fs = 2E6; +N = 1024; +num_frames = length(s)/N; +h = hanning(N); +XdB = zeros(N/2,1); + +for i=1:num_frames + x = s((i-1)*N+1:i*N); + X = fft(x .* h); + XdB += 20*log10(abs(X(1:N/2))); +end + +XdB /= num_frames; +XdB -= max(20*log10(N)); + +figure(1) +clf +plot((0:N/2-1)*Fs/(1000*N), XdB) +grid +ylabel('Amplitude dB') +xlabel('Frequency (kHz)'); +axis([0 Fs/(2*1000) -30 80]) + +figure(2) +clf +plot(s) + + diff --git a/codec2/branches/0.7/octave/adcres.m b/codec2/branches/0.7/octave/adcres.m new file mode 100644 index 00000000..69dae0d4 --- /dev/null +++ b/codec2/branches/0.7/octave/adcres.m @@ -0,0 +1,56 @@ +% adcres.m +% David Rowe 18 Feb 2015 +% +% ADC resamping simulation, IIR tuner development. + +% [ ] quantisation of ADC +% [ ] SNR at ADC input, SNR at resampler output +% [X] decimation to 50 kHz +% [X] 40dB ish rejection (test) +% [X] visualise pass band flatness + +graphics_toolkit ("gnuplot"); + +fs = 2E6; +f1 = 500E3; +f2 = f1 + 8E3; +f3 = f1 - 7E3; +f4 = f1 - 207E3; +t = (0:(fs-1)); +M = 45; +beta1 = 0.999; +beta2 = 1 - (1-beta1)*M; + +s1 = [fs zeros(1,fs-1)]; % noise floor, continuous interferers +s2 = 100*4*cos(t*2*pi*f2/fs); % wanted signal 40dB above interferers +s3 = 100*2*cos(t*2*pi*f3/fs); +s4 = 100*2*cos(t*2*pi*f4/fs); % interferer at same level +s = s1 + s2 + s3 + s4; + +s2 = filter(1,[1 0 beta1],s); % BPF at fs/4 +s3 = s2(1:M:length(s2)); % decimate +s4 = filter([1 0 beta2],1,s3); % flatten filter response again + +figure(1) +subplot(211) +plot(20*log10(abs(fft(s)/fs))) +grid +axis([0 fs/2 -10 50]) +title('Input to ADC'); +subplot(212) +plot(20*log10(abs(fft(s2/fs)))) +grid +axis([0 fs/2 -10 70]) +title('After BPF'); + +figure(2) +subplot(211) +plot(20*log10(abs(fft(s3)/fs))) +grid +axis([0 fs/2/M -10 50]) +title('After Decimation'); +subplot(212) +plot(20*log10(abs(fft(s4)/fs))) +grid +title('After Equaliser'); +axis([0 fs/2/M -10 50]) diff --git a/codec2/branches/0.7/octave/autotest.m b/codec2/branches/0.7/octave/autotest.m new file mode 100644 index 00000000..7a83184b --- /dev/null +++ b/codec2/branches/0.7/octave/autotest.m @@ -0,0 +1,114 @@ +% autotest.m +% David Rowe Mar 2015 +% +% Helper functions to plot output of C verson and difference between Octave and C versions + +1; + +function stem_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec) + global no_plot_list; + + if find(no_plot_list == plotnum) + return; + end + figure(plotnum) + subplot(subplotnum) + stem(sig,'g;Octave version;'); + hold on; + stem(error,'r;Octave - C version (hopefully 0);'); + hold off; + if nargin == 6 + axis(axisvec); + end + title(titlestr); +endfunction + + +function plot_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec) + global no_plot_list; + + if find(no_plot_list == plotnum) + return; + end + + figure(plotnum) + subplot(subplotnum) + plot(sig,'g;Octave version;'); + hold on; + plot(error,'r;Octave - C version (hopefully 0);'); + hold off; + if nargin == 6 + axis(axisvec); + end + title(titlestr); +endfunction + + +function check(a, b, test_name, tol, its_an_angle = 0) + global passes; + global fails; + + if nargin == 3 + tol = 1E-3; + end + + [m n] = size(a); + if m > n + ll = m; + else + ll = n; + end + + printf("%s", test_name); + for i=1:(25-length(test_name)) + printf("."); + end + printf(": "); + + if its_an_angle + % take into account pi is close to -pi for angles in rads + e = sum(sum(abs(exp(j*a) - exp(j*b)))/ll); + else + e = sum(sum(abs(a - b))/ll); + end + + if e < tol + printf("OK\n"); + passes++; + else + printf("FAIL (%f)\n",e); + fails++; + end +endfunction + +function check_no_abs(a, b, test_name) + global passes; + global fails; + + tol = 1E-3; + + [m n] = size(a); + if m > n + ll = m; + else + ll = n; + end + + printf("%s", test_name); + for i=1:(25-length(test_name)) + printf("."); + end + printf(": "); + + e = sum(sum(a - b)/ll); + + if e < tol + printf("OK\n"); + passes++; + else + printf("FAIL (%f)\n",e); + fails++; + end +endfunction + + diff --git a/codec2/branches/0.7/octave/av_imp.m b/codec2/branches/0.7/octave/av_imp.m new file mode 100644 index 00000000..8b7fa608 --- /dev/null +++ b/codec2/branches/0.7/octave/av_imp.m @@ -0,0 +1,43 @@ +% av_imp.m +% David Rowe Aug 2012 +% Averages the impulse response samples + +function imp = av_imp(imp_filename, period_in_secs, st, en) + f = fopen(imp_filename,"rb"); + s = fread(f, Inf, "short")'; + + Fs = 8000; + n = period_in_secs * Fs; + + [r c] = size(s); + + imp = zeros(1,n); + for i=1:n:c-n + imp = imp + s(i:i+n-1); + endfor + + % user supplies start and end samples after viweing plot + + if (nargin == 4) + imp = imp(st:en); + end + + % normalise + + imp /= sqrt(sum(imp .^ 2)); + + [h w] = freqz(imp, 1, 4000); + + figure(1); + clf; + plot(imp); + + figure(2); + clf; + subplot(211) + plot(10*log10(abs(h))) + subplot(212) + plot(angle(h)) + +endfunction + diff --git a/codec2/branches/0.7/octave/bandpasssampling.m b/codec2/branches/0.7/octave/bandpasssampling.m new file mode 100644 index 00000000..9a2a4efc --- /dev/null +++ b/codec2/branches/0.7/octave/bandpasssampling.m @@ -0,0 +1,34 @@ +% bandpasssampling.m +% David Rowe 23 Feb 2015 +% +% Band pass sampling example + +graphics_toolkit ("gnuplot"); + +t = 0:1E-3:1-1E-3; +f1 = 5; +f2 = 105; + +x = 1:10:length(s1); + +s1 = cos(2*pi*f1*t); +s1_sampled = s1(x); + +s2 = cos(2*pi*f2*t); +s2_sampled = s2(x); + +figure(1) +subplot(211) +plot(t,s1) +title('5Hz signal sampled at 100 Hz'); +subplot(212) +stem(x*1E-3, s1_sampled,'r') +xlabel('Time (s)'); + +figure(2) +subplot(211) +plot(t,s2) +title('105Hz signal sampled at 100 Hz'); +subplot(212) +stem(x*1E-3, s2_sampled,'r') +xlabel('Time (s)'); diff --git a/codec2/branches/0.7/octave/bfq19ssa.m b/codec2/branches/0.7/octave/bfq19ssa.m new file mode 100644 index 00000000..b5dbf2b2 --- /dev/null +++ b/codec2/branches/0.7/octave/bfq19ssa.m @@ -0,0 +1,83 @@ +% bfq19ssa.m +% +% David Rowe Dec 2015 +% +% Working for 100mW class A small signal amp using the BFQ19 + +rfdesign; + +w = 2*pi*150E6; + +% BFQ19 Vce=10V Ic=50mA 100MHz + +S11 = 0.251*exp(j*(-142.7)*pi/180); +S21 = 20.28*exp(j*(103.1)*pi/180); +S12 = 0.030*exp(j*(72.9)*pi/180); +S22 = 0.290*exp(j*(-61.9)*pi/180); + +% Lets check stability + +Ds = S11*S22-S12*S21; +Knum = 1 + abs(Ds)^2 - abs(S11)^2 - abs(S22)^2; +Kden = 2*abs(S21)*abs(S12); +K = Knum/Kden +figure(1); +clf +scCreate; + +if K < 1 + C1 = S11 - Ds*conj(S22); + C2 = S22 - Ds*conj(S11); + rs1 = conj(C1)/(abs(S11)^2-abs(Ds)^2); % centre of input stability circle + ps1 = abs(S12*S21/(abs(S11)^2-abs(Ds)^2)); % radius of input stability circle + rs2 = conj(C2)/(abs(S22)^2-abs(Ds)^2); % centre of input stability circle + ps2 = abs(S12*S21/(abs(S22)^2-abs(Ds)^2)); % radius of input stability circle + + s(1,1)=S11; s(1,2)=S12; s(2,1)=S21; s(2,2)=S22; + plotStabilityCircles(s) +end + +% determine collector load Rl for our desired power output + +P = 0.1; +Irms = 0.02; +Rl = P/(Irms*Irms); + +% choose gammaL based on Rl + +zo = Rl/50; +[magL,angleL] = ztog(zo); +gammaL = magL*exp(j*angleL*pi/180); + +% calculate gammaS and Zi and plot + +gammaS = conj(S11 + ((S12*S21*gammaL)/(1 - (gammaL*S22)))); +[zi Zi] = gtoz(abs(gammaS), angle(gammaS)*180/pi,50); + +scAddPoint(zi); +scAddPoint(zo); + +% Design ouput matching network + +Ro = 50; +[Xs Xp] = z_match(Ro, Rl) +Cos = 1/(w*Xs); +Lop = Xp/w; + +printf("Output Matching:\n"); +printf(" Rl = %3.1f Ro = %3.1f\n", Rl, Ro); +printf(" Xp = %3.1f Xs = %3.1f\n", Xp, Xs); +printf(" Cos = %3.1f pF Lop = %3.1f nH\n", Cos*1E12, Lop*1E9); + +% design input matching network between 50 ohms source and 10 ohms at base + +Rb = real(Zi); Rs = 50; + +[Xs Xp] = z_match(Rb, Rs); + +Lip = Xp/w; +Cis = 1/(w*Xs); + +printf("Input Matching:\n"); +printf(" Xs = %3.1f Xp = %3.1f\n", Xs, Xp); +printf(" Lp = %3.1f nH Cs = %3.1f pF\n", Lip*1E9, Cis*1E12); diff --git a/codec2/branches/0.7/octave/bpf.m b/codec2/branches/0.7/octave/bpf.m new file mode 100644 index 00000000..9e0af8fb --- /dev/null +++ b/codec2/branches/0.7/octave/bpf.m @@ -0,0 +1,31 @@ +% bpf.m +% David Rowe April 2015 +% +% Design 400-2600 Hz BPF and save coeffs + +1; + +function write_c_array(filename, arrayname, vec) + + m = length(vec); + + f=fopen(filename,"wt"); + fprintf(f,"#define %s_N %d\n\n", toupper(arrayname), m); + fprintf(f,"float %s[]={\n", arrayname); + for r=1:m + if r < m + fprintf(f, " %f,\n", vec(r)); + else + fprintf(f, " %f\n};", vec(r)); + end + end + + fclose(f); +endfunction + +b=firls(100,[0 250 300 2600 2700 4000]/4000,[0.01 0.01 1 1 0.01 0.01]); +freqz(b) +write_c_array("../src/bpfb.h", "bpfb", b) + +% C header file of noise samples so C version gives extacly the same results + diff --git a/codec2/branches/0.7/octave/bpsk.m b/codec2/branches/0.7/octave/bpsk.m new file mode 100644 index 00000000..91dfbc11 --- /dev/null +++ b/codec2/branches/0.7/octave/bpsk.m @@ -0,0 +1,284 @@ +% bpsk.m +% David Rowe Mar 2017 +% +% Simulate BPSK and DPSK with varoous phase detection schemes + +1; + +% Differential BPSK detector (m=2) +% ML detection which gains about 0.5dB (m=3, m=4) +% +% Based on JPL publication 89-38 "Multiple Symbol Differential +% Detection of Uncoded and Trellis Coded MPSK" by Divsalar, Simon, +% Shahshahani. Thanks Johhn Gibbs NN7F for advice. + +function rx_symb = dbpsk_demod(m, r) + tx_set = [1 -1]; + + if m == 2 + + % regular DBPSK detection + + rx_symb(i) = r(1) * r(2)'/(abs(r(2))); + + else + + % ML DBPSK detection + + max_eta = 0; rx_symb(i) = tx_set(1); + + for k=1:2 + for k_1=1:2 + for k_2=1:2 + + if m == 3 + eta = abs(r(3) + r(1)*tx_set(k)'*tx_set(k_1)' + r(2)*tx_set(k_1)')^2; + end + + if m == 4 + eta = abs(r(4) + r(1)*tx_set(k)'*tx_set(k_1)'*tx_set(k_2)' + r(2)*tx_set(k_1)'*tx_set(k_2)' + r(3)*tx_set(k_2)')^2; + end + + %printf(" %d %d %f \n", k_1, k, eta); + + if eta > max_eta + max_eta = eta; + rx_symb(i) = tx_set(k); + end + + end + end + end + end +endfunction + + +function sim_out = run_sim(sim_in) + Rs = 50; + + Nbits = sim_in.Nbits; + EbNodB = sim_in.EbNodB; + dbpsk = sim_in.dbpsk; + verbose = sim_in.verbose; + m = sim_in.m; + phase_est_mem = sim_in.phase_est_mem; + assert(mod(phase_est_mem,2) == 1, "phase_est_mem must be odd"); + phase_est_delay = floor(phase_est_mem/2); + printf("phase_est_mem: %d phase_est_delay: %d\n", phase_est_mem, phase_est_delay); + + woffset = 2*pi*sim_in.freq_offset_hz/Rs; + + + for nn=1:length(EbNodB) + EbNo = 10 .^ (EbNodB(nn)/10); + variance = 1/(EbNo/2); + noise = sqrt(variance)*(0.5*randn(1,Nbits) + j*0.5*randn(1,Nbits)); + + tx = zeros(1,Nbits); + rx = zeros(1,Nbits); + tx_bits = rand(1,Nbits) > 0.5; + prev_tx = 1; + prev_rx = 1; + r = ones(1,max(4,phase_est_mem)); + phase_amb = 0; + phase_offset = sim_in.phase_offset + + phase_offset_log = zeros(1,Nbits); + phase_amb_log = zeros(1,Nbits); + phase_est_stripped = zeros(1,Nbits); + phase_est = zeros(1,Nbits); + + Nerrs = 0; + for i=1:Nbits + if dbpsk + tx(i) = prev_tx * exp(j*pi*tx_bits(i)); + prev_tx = tx(i); + else + tx(i) = 1 - 2*tx_bits(i); + end + + rx(i) = tx(i)*exp(j*phase_offset) + noise(i); + phase_offset_log(i) = phase_offset; + phase_offset += woffset; + if (phase_offset > pi) + phase_offset -= 2*pi; + end + + r(2:phase_est_mem) = r(1:phase_est_mem-1); + r(1) = rx(i); + + if dbpsk + rx_symb(i) = dbpsk_demod(m, r); + else + rx_symb(i) = rx(i); + + if phase_est_mem + + if i >= phase_est_mem + + % demod symbol at centre of phase est window + + centre = i - phase_est_delay; + + % modulation strip + + stripped = r(1:phase_est_mem) .^ 2; + + phase_est_stripped(centre) = angle(sum(stripped))/2; + + % determine if phase has jumped from - -> + + + if (phase_est_stripped(centre-1) < -pi/4) && (phase_est_stripped(centre) > pi/4) + %printf("- -> +\n"); + phase_amb -= pi; + if (phase_amb < -pi) + phase_amb += 2*pi; + end + end + + % determine if phase has jumped from + -> - + + if (phase_est_stripped(centre-1) > pi/4) && (phase_est_stripped(centre) < -pi/4) + %printf("+ -> -\n"); + phase_amb += pi; + if (phase_amb > pi) + phase_amb -= 2*pi; + end + end + + phase_amb_log(centre) = phase_amb; + phase_est(centre) = phase_est_stripped(centre) + phase_amb; + + % keep phase est in range of -pi .. pi to aid plotting + + if (phase_est(centre) < -pi) + phase_est(centre) += 2*pi; + end + if (phase_est(centre) > pi) + phase_est(centre) -= 2*pi; + end + + rx_symb(centre) *= exp(-j*phase_est(centre)); + end + end + end + end + + % if using block based phase est, strip off first few and last few + % symbols where phase ests are invalid + + st = phase_est_delay+1; + %en = Nbits-phase_est_delay; + en = 50; + rx_bits = real(rx_symb) < 0; + errors = xor(tx_bits, rx_bits); + Nerrs = sum(errors(st:en)); + printf("EbNodB: %3.2f BER: %4.3f Nbits: %d Nerrs: %d\n", EbNodB(nn), Nerrs/(en-st+1), (en-st+1), Nerrs); + + if verbose + figure(1); clf; + plot(rx_symb(st:en),'+'); + axis([-2 2 -2 2]); + figure(2); clf; + plot(phase_offset_log(st:en),'b+;phase offset;', 'markersize', 10); + hold on; + plot(phase_amb_log(st:en),'c-;phase amb;'); + plot(phase_est_stripped(st:en),'ro;phase est stripped;'); + plot(phase_est(st:en),'g*;phase est;'); + hold off; + axis([1 en-st+1 -pi pi]) + legend('boxoff'); + figure(3); clf; + plot(errors(st:en),'+'); + axis([1 en-st+1 -0.5 1.5]); + end + + sim_out.ber(nn) = Nerrs/Nbits; + end +endfunction + + +function run_curves + sim_in.verbose = 0; + sim_in.Nbits = 10000; + sim_in.EbNodB = 0:6; + sim_in.dbpsk = 0; + sim_in.m = 2; + sim_in.phase_est_mem = 0; + sim_in.phase_offset = 0; + + bpsk_out = run_sim(sim_in); + + sim_in.phase_offset = pi/4; + sim_in.phase_est_mem = 5; + bpsk_out_5 = run_sim(sim_in); + sim_in.phase_est_mem = 10; + bpsk_out_10 = run_sim(sim_in); + sim_in.phase_est_mem = 20; + bpsk_out_20 = run_sim(sim_in); + + figure(3); clf; + semilogy(sim_in.EbNodB, bpsk_out.ber,'b+-;BPSK;'); + hold on; + semilogy(sim_in.EbNodB, bpsk_out_5.ber,'g+-;BPSK 5 pt phase est;'); + semilogy(sim_in.EbNodB, bpsk_out_10.ber,'c+-;BPSK 10 pt phase est;'); + semilogy(sim_in.EbNodB, bpsk_out_20.ber,'k+-;BPSK 20 pt phase est;'); + hold off; + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; + legend('boxoff'); + title('Coherent Modn Stripped BPSK'); + print -depsc bpsk_coherent.eps + +#{ + sim_in.dbpsk = 1; + dbpsk_out_2 = run_sim(sim_in); + + sim_in.m = 3; + dbpsk_out_3 = run_sim(sim_in); + sim_in.m = 4; + dbpsk_out_4 = run_sim(sim_in); + + figure(4); clf; + semilogy(sim_in.EbNodB, bpsk_out.ber,'b+-;BPSK;'); + hold on; + semilogy(sim_in.EbNodB, dbpsk_out_2.ber,'g+-;DBPSK m=2;'); + semilogy(sim_in.EbNodB, dbpsk_out_3.ber,'c+-;DBPSK m=3;'); + semilogy(sim_in.EbNodB, dbpsk_out_4.ber,'k+-;DBPSK m=4;'); + hold off; + print -depsc dbpsk_ml.eps + + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; + legend('boxoff'); + title('ML DBPSK'); +#} +end + + +function run_single + sim_in.Nbits = 1000; + sim_in.EbNodB = 4; + sim_in.dbpsk = 0; + sim_in.m = 2; + sim_in.phase_est_mem = 11; + sim_in.verbose = 1; + sim_in.phase_offset = 0; + sim_in.freq_offset_hz = 1; + + run_sim(sim_in); +end + + +format; +more off; +rand('seed',1); +randn('seed',1); + +run_single +%run_curves + + + diff --git a/codec2/branches/0.7/octave/c2wideband_batch.m b/codec2/branches/0.7/octave/c2wideband_batch.m new file mode 100644 index 00000000..c4ba7147 --- /dev/null +++ b/codec2/branches/0.7/octave/c2wideband_batch.m @@ -0,0 +1,316 @@ +% c2wideband_batch.m +% +% Copyright David Rowe 2017 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +#{ + + Octave script to batch process model parameters for wideband Codec 2. + + Outputs a set of model parameters that can be fed to c2sim for + listening tests. The companion c2wideband_fbf.m script is used to + visualise the processing frame by frame + + c2sim -> dump files -> c2wideband_batch.m -> output model params -> c2sim -> play + + Usage: + + Build codec2 with -DDUMP (see codec2-dev/README), then generate dump files: + + ~/codec2-dev/build_linux/src$ ./c2sim ~/Desktop/c2_hd/speech_orig_16k.wav --Fs 16000 --dump speech + + Start Octave and generate the map file, this only needs to be done once: + + $ cd ~/codec2-dev/octave + $ octave + octave:1> c2wideband_batch("../build_linux/src/speech", "mode", "generate map") + + Then to run batch simulation and generate output speech: + + octave:1> c2wideband_batch("../build_linux/src/speech"); + + ~/codec2-dev/build_linux/src$ ./c2sim ~/Desktop/c2_hd/speech_orig_16k.wav --Fs 16000 --phase0 --postfilter --amread speech_am.out --hmread speech_hm.out -o | play -t raw -r 16000 -s -2 - +#} + + +function [surface mean_f] = c2wideband_batch(input_prefix, varargin) + newamp; + more off; + + max_amp = 160; + mean_f = []; + + % defaults + + synth_phase = output = 1; + output_prefix = input_prefix; + fit_order = 0; + mode = "dct2"; + + % parse variable argument list + + if (length (varargin) > 0) + + ind = arg_exists(varargin, "mode"); + if ind + mode = varargin{ind+1}; + end + + % check for the "output_prefix" option + + ind = arg_exists(varargin, "output_prefix"); + if ind + output_prefix = varargin{ind+1}; + end + + ind = arg_exists(varargin, "no_output"); + if ind + output = 0; + synth_phase = 0; + end + end + + if output && !strcmp(mode,"generate map") + printf("output_prefix: %s\n", output_prefix); + end + + model_name = strcat(input_prefix,"_model.txt"); + model = load(model_name); + [frames nc] = size(model); + + % Choose experiment to run test here ----------------------- + + if strcmp(mode, "generate map") + generate_map(model, K=30, "c2wideband_map"); + output = 0; + end + if strcmp(mode, "dct2") + [model_ surface] = experiment_rate_K_dct2(model, 1); + frames_out = rows(model_); + end + + % ---------------------------------------------------- + + if output + Am_out_name = sprintf("%s_am.out", output_prefix); + fam = fopen(Am_out_name,"wb"); + + if synth_phase + Hm_out_name = sprintf("%s_hm.out", output_prefix); + fhm = fopen(Hm_out_name,"wb"); + end + + for f=1:frames_out + %printf("%d ", f); + Wo = model_(f,1); L = min([model_(f,2) max_amp-1]); Am = model_(f,3:(L+2)); + if Wo*L > pi + printf("Problem: %d Wo*L > pi\n", f); + end + + Am_ = zeros(1,max_amp); Am_(2:L) = Am(1:L-1); fwrite(fam, Am_, "float32"); + + if synth_phase + + % synthesis phase spectra from magnitiude spectra using minimum phase techniques + + fft_enc = 256; + phase = determine_phase(model_, f, fft_enc); + assert(length(phase) == fft_enc); + + % sample phase at centre of each harmonic, not 1st entry Hm[1] in octave Hm[0] in C + % is not used + + Hm = zeros(1, 2*max_amp); + for m=1:L + b = round(m*Wo*fft_enc/(2*pi)); + Hm(2*m) = cos(phase(b)); + Hm(2*m+1) = -sin(phase(b)); + end + fwrite(fhm, Hm, "float32"); + end + end + + fclose(fam); + if synth_phase + fclose(fhm); + end + end % if output ..... + + printf("\n") + +endfunction + + +function ind = arg_exists(v, str) + ind = 0; + for i=1:length(v) + if strcmp(v{i}, str) + ind = i; + end + end +endfunction + + +% Create "map" from a training database. The map tells us which order +% to read out and quantise DCT coeffs. Could be approximated by a +% zig-zag pattern. +% +% Example 3x3 map in a zig-zag pattern, so (1,1) is first coeff, (1,2) +% 2nd .... +% +% 1 2 6 +% 2 5 7 +% 4 8 9 +% +% TODO: [ ] Come up with a better name than +% [ ] Script to convert this to a C header file. + +function generate_map(model, K, map_filename) + newamp; + c2wideband_const; + + [frames nc] = size(model); + surface = resample_const_rate_f_mel(model, K, Fs); + [nr nc] = size(surface); + asurf = surface(1:dec:nr,:); + [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(asurf, Nt, K); + + %printf("non zero coeffs: %d\n", sum(sum(map == 1))); + figure(2); clf; + mesh(map); + + printf("generating map file: %s\n", map_filename); + save("-ascii", map_filename, "map"); +endfunction + + +% --------------------------------------------------------------------------------------- +% rate K mel-resampling, high end correction, and DCT experiment workhorse + +function [model_ rate_K_surface] = experiment_rate_K_dct2(model, plots=1) + newamp; + c2wideband_const; + + [frames nc] = size(model); + + % break into blocks of (Nt time samples) x (K freq samples) + + Nblocks = floor(frames/(Nt*dec)); + %printf("frames: %d Nblocks: %d\n", frames, Nblocks); + + % map that defines order we read out and quantise DCT coeffs + % TODO: for C port we need an Octave function to write Map to a C + % include file + + map = load("c2wideband_map"); + + % create arrays to reverse map quantiser_num to r,c Luts + + rmap = cmap = zeros(1,Nt*K); + for r=1:Nt + for c=1:K + quantiser_num = map(r,c); + rmap(quantiser_num) = r; + cmap(quantiser_num) = c; + end + end + + % per-block processing ---------------------------------------------------- + + % init a bunch of output variables + + rate_K_surface_ = zeros(Nblocks*Nt*dec, K); + sumnz = zeros(1,Nblocks); + dct2_sd = zeros(1,Nblocks); + model_ = []; + + for n=1:Nblocks + st = (n-1)*dec*Nt+1; en = st + dec*Nt - 1; + %printf("st: %d en: %d\n", st, en); + + [model_block_ adct2_sd qn rate_K_surface_block rate_K_surface_block_] = wideband_enc_dec(model(st:en,:), rmap, cmap); + + model_ = [model_; model_block_]; + + % log these for plotting/development + + rate_K_surface(st:en,:) = rate_K_surface_block; + rate_K_surface_(st:en,:) = rate_K_surface_block_; + dct2_sd(n) = adct2_sd; + sumnz(n) = qn; + end + + if plots + figure(4); clf; plot(sumnz); hold on; + plot([1 length(sumnz)],[mean(sumnz) mean(sumnz)]); hold off; title('Non Zero'); + figure(5); clf; plot(dct2_sd); title('DCT SD'); + end + printf("average dct spectral distortion: %3.2f dB\n", mean(dct2_sd)); + printf("mean number of coeffs/DCT: %3.2f/%d\n", mean(sumnz), Nt*K); + printf("coeffs/second: %3.2f\n", mean(sumnz)/(Nt*Tf*dec)); + printf("bits/s: %3.2f\n", 2.9*mean(sumnz)/(Nt*Tf*dec)); + + % this measure just works on 20ms frames, not sure if that's correct + + dist = std((rate_K_surface_(1:dec:Nblocks*Nt*dec,:) - rate_K_surface(1:dec:Nblocks*Nt*dec,:))'); + + if plots + figure(1); clf; plot(dist); title('Rate K SD'); + printf("Rate K spectral distortion mean: %3.2f dB var: %3.2f\n", mean(dist), var(dist)); + end +endfunction + + +% Encode/decoder a 160ms block of model parameters +% TODO: (i) quantisation of DCT coeffs (ii) break into separate encoder and decoder functions + +function [model_block_ dct2_sd qn rate_K_surface_block rate_K_surface_block_] = wideband_enc_dec(model_block, rmap, cmap) + c2wideband_const; + + sim_quant = 1; % used to simulate quantisation, set to 1,2,4, etc + dist_dB = 2; % use enough coefficients to get this distortion ond DCT coeffs + + % Resample variable rate L vectors to fixed length rate K. We have + % left high end correction out for now, this is less of an issue + % with a higher K + + [rate_K_surface_block rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model_block, K, Fs); + + % decimate down to 20ms time resolution, and DCT + + D = dct2(rate_K_surface_block(1:dec:Nt*dec,:)); + + % So D is the 2D block of DCT coeffs at the encoder. We want to + % create a quantised version at the "decoder" E. This loop copies + % DCTs coeffs from D to E, until we get beneath a distortion + % threshold. + + % This is essentially variable rate quantisation, but gives us + % some idea of the final bit rate. In practice we will also need + % to constrain the total number of bits (ie bit rate), and + % quantise each coefficient. + + % Turns out than mean SD (across many blocks/frames) is about the + % same in the DCT domain as the rate K domain. So we can just + % measure MSE between D and E to estimate mean SD of the rate K + % vectors after quantisation. + + E = mapped = zeros(Nt,K); + + qn = 0; + adct2_sd = mean(std(D-E)); + while adct2_sd > dist_dB + qn++; + E(rmap(qn), cmap(qn)) = sim_quant*round(D(rmap(qn), cmap(qn))/sim_quant); + adct2_sd = mean(std(D-E)); + %printf("qn %d %f\n", qn, adct2_sd); + end + + % note neat trick to interpolate to 10ms frames despite dec to 20ms, this means + % we don't need a separate decode side interpolator. + + dct2_sd = mean(std(D-E)); + rate_K_surface_block_ = idct2([sqrt(dec)*E; zeros(Nt*(dec-1), K)]); + model_block_ = resample_rate_L(model_block, rate_K_surface_block_, rate_K_sample_freqs_kHz, Fs); +endfunction diff --git a/codec2/branches/0.7/octave/c2wideband_const.m b/codec2/branches/0.7/octave/c2wideband_const.m new file mode 100644 index 00000000..891fbb48 --- /dev/null +++ b/codec2/branches/0.7/octave/c2wideband_const.m @@ -0,0 +1,25 @@ +% c2wideband_const.m +% David Rowe July 2017 +% +% Constants for wideband Codec 2, bit like #define for C + +Fs = 16000; % sampel rate in Hz +K = 30; % number of Mel spaced amplitude samples + +Tf = 0.01; % frame period in seconds + +dec = 2; % decimation factor. 10ms update of the core + % sinusuodial codec is rather fast and reducing it to + % 20ms makes very little difference in quality, but + % halves the data going into the DCT/quantisation. + % While the DCT should encode highly correlated data + % like 10ms frame efficiently, there is some noise in + % the core paraneters estimation so nice to use a lower + % frame rate if possible. + +Nt = 8; % number of blocks in time. Trade off between latency + % and coding efficiency. If the DCT has larger blocks to + % play with it can remove more correlation, up to a limit + % where the data is no longer correlated in time or freq. + % Also set to match LDPC code frame size + diff --git a/codec2/branches/0.7/octave/c2wideband_fbf.m b/codec2/branches/0.7/octave/c2wideband_fbf.m new file mode 100644 index 00000000..4d687048 --- /dev/null +++ b/codec2/branches/0.7/octave/c2wideband_fbf.m @@ -0,0 +1,92 @@ +% c2wideband_fbf.m +% +% Copyright David Rowe 2017 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +% Interactive Octave script to explore frame by frame operation of +% wideband Codc 2. + +#{ + Make sure codec2-dev is compiled with the -DDUMP option - see README for + instructions. + + Usage: + ~/codec2-dev/build_linux/src$ ./c2sim ~/Desktop/c2_hd/speech_orig_16k.wav --Fs 16000 --dump speech + + $ cd ~/codec2-dev/octave + $ octave + octave:1> c2wideband_fbf("../build_linux/src/speech") +#} + +function c2wideband_fbf(samname, f=70, varargin) + more off; + newamp; + + Fs = 16000; Fs2 = Fs/2; K = 30; + + % load up text files dumped from c2sim --------------------------------------- + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + [frames tmp] = size(model); + + % Keyboard loop -------------------------------------------------------------- + + k = ' '; + do + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + figure(1); clf; plot(s); axis([1 length(s) -20000 20000]); + + Wo = model(f,1); L = model(f,2); Am = model(f,3:(L+2)); AmdB = 20*log10(Am); + Am_freqs_kHz = (1:L)*Wo*Fs2/(1000*pi); + + [rate_K_vec rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model(f,:), K, Fs); + + % plots ---------------------------------- + + figure(2); clf; + plot((1:L)*Wo*Fs2/pi, AmdB,";AmdB;g+-"); + axis([1 Fs2 -20 80]); + hold on; + stem(rate_K_sample_freqs_kHz*1000, rate_K_vec, ";rate K;b+-"); + + [model_ AmdB_] = resample_rate_L(model(f,:), rate_K_vec, rate_K_sample_freqs_kHz, Fs); + AmdB_ = AmdB_(1:L); + + plot((1:L)*Wo*Fs2/pi, AmdB_,";AmdB;r+-"); + hold off; + + % interactive menu ------------------------------------------ + + printf("\rframe: %d menu: n-next b-back q-quit [%d]", f); + fflush(stdout); + k = kbhit(); + + if k == 'n' + f = f + 1; + endif + if k == 'b' + f = f - 1; + endif + until (k == 'q') + printf("\n"); + +endfunction + + +function ind = arg_exists(v, str) + ind = 0; + for i=1:length(v) + if strcmp(v{i}, str) + ind = i; + end + end +endfunction + + diff --git a/codec2/branches/0.7/octave/cbphase.m b/codec2/branches/0.7/octave/cbphase.m new file mode 100644 index 00000000..8e82da1c --- /dev/null +++ b/codec2/branches/0.7/octave/cbphase.m @@ -0,0 +1,98 @@ +% cbphase.m +% David Rowe Aug 2012 +% Used to experiment with critical band phase perception and smoothing + +function cbphase + + Wo = 100.0*pi/4000; + L = floor(pi/Wo); + + A = zeros(1,L); + phi = zeros(1,L); + + % three harmonics in this band + + b = 4; a = b-1; c = b+1; + + % set up phases and mags for 2nd order system (see phasesecord.m) + + wres = b*Wo; + phi(a) = 3*pi/4 + wres; + phi(b) = pi/2 + wres; + phi(c) = pi/4 + wres; + + A(a) = 0.707; + A(b) = 1; + A(c) = 0.707; + + % add linear component + + phi(1) = pi; + phi(2:L) = phi(2:L) + (2:L)*phi(1); + phi = phi - 2*pi*(floor(phi/(2*pi)) + 0.5); + + N = 16000; + Nplot = 250; + s = zeros(1,N); + + for m=a:c + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi(m)); + s = s + s_m; + endfor + + figure(2); + clf; + subplot(211) + plot((1:L)*Wo*4000/pi, A,'+'); + subplot(212) + plot((1:L)*Wo*4000/pi, phi,'+'); + + %v = A(a)*exp(j*phi(a)) + A(b)*exp(j*phi(b)) + A(c)*exp(j*phi(c)); + %compass(v,"r") + %hold off; + + % est phi1 + + diff = phi(b) - phi(a) + sumi = sin(diff); + sumr = cos(diff); + diff = phi(c) - phi(b) + sumi += sin(diff); + sumr += cos(diff); + phi1_ = atan2(sumi, sumr) + s_v = cos(Wo*(0:(N-1)) + phi1_); + + figure(1); + clf; + subplot(211) + plot(s(1:Nplot)); + hold on; + plot(s_v(1:Nplot),"r"); + hold off; + + % build (hopefully) perceptually similar phase + + phi_(a) = a*phi1_; + phi_(b) = b*phi1_; + phi_(c) = c*phi1_; + + s_ = zeros(1,N); + + for m=a:c + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi_(m)); + s_ = s_ + s_m; + endfor + + subplot(212) + plot(s_(1:Nplot)); + + gain = 8000; + fs=fopen("orig_ph.raw","wb"); + fwrite(fs,gain*s,"short"); + fclose(fs); + fs=fopen("mod_ph.raw","wb"); + fwrite(fs,gain*s_,"short"); + fclose(fs); + +endfunction + diff --git a/codec2/branches/0.7/octave/cellmodem.m b/codec2/branches/0.7/octave/cellmodem.m new file mode 100644 index 00000000..37005399 --- /dev/null +++ b/codec2/branches/0.7/octave/cellmodem.m @@ -0,0 +1,137 @@ +% cellmodem.m +% David Rowe May 2005 +% +% Simulation of modem for low rate date through a cell phone codec +% +% Ideas: +% + insert low rate codec +% + generate bunch of symbols, run through codec, measure MSE, choose best set +% + measure probablility of error, "distance" from other symbols +% + can we use VQ training algorithm for this? Start with 2 symbols, +% pass through channel, measure MSE, split again? +% + start with cmd line version of codec, frame synchronous +% + add symbol timing estimator later +% + try different frame rates +% + simulate impairments like HP/LP filtering. Can we correct for this? +% + pilots symbols so we can use energy as well? +% + set of F0 as well +% + LSP quantisers preferrentially preserve peaks, so three peaks is a +% reasonable signal set. Modulate position and bandwidth to creat +% symbol set. Maybe 50 or 100 Hz grid for LSPs, evaluate that some how. + +graphics_toolkit ("gnuplot"); +rand('state',1); +lsp; + +% given a vector of LSP symbols, constructs a synthesised speech signals +% anfd runs it through a codec + +function [w__log mse] = run_sim(sim_in, w_log) + N = sim_in.N; + Wo = sim_in.Wo; + frames = sim_in.frames; + lpc_order = sim_in.lpc_order; + + s = []; + w__log = []; + L = floor(pi/Wo); + phi = zeros(1,L); + + for f=1:frames + + % synthesise speech signal + + a=lsptoa(w_log(f,:)); + + ex = zeros(1,N); + for m=1:L + phi(m) += Wo*m*N; + ex += cos(phi(m) + Wo*m*(0:N-1)); + end + + s = [s filter(1, a, ex)]; + end + + % play through codec + + s *= sim_in.gain; + f=fopen("in.raw","wb"); + fwrite(f,s,"short"); + fclose(f); + system(sim_in.codec_cmd); + f=fopen("out.raw","rb"); + s_ = fread(f,Inf,"short"); + fclose(f); + + % extract received symbols from channel and evaluate + + mse = zeros(1,frames); + for f=1:frames + a_ = lpcauto(s_((f-1)*sim_in.N+1:f*N), lpc_order); + w_ = atolsp(a_); + w__log = [w__log; w_]; + error = w__log(f,:) - w_log(f,:); + mse(f) = error*error'; + end +endfunction + +% constants ----------------------------------------------------- + +sim_in.codec_cmd = "speexenc --bitrate 4000 in.raw - | speexdec - out.raw"; + +lpc_order = sim_in.lpc_order = 6; +Fs = sim_in.Fs = 8000; + sim_in.Fo = 100; % pitch frequency of voice + sim_in.Wo = 2*pi*Fo/Fs; % pitch in rads +N = sim_in.N = Fs*0.04; % frame length +frames = sim_in.frames = 1000; % frames to play through codec + sim_in.gain = 100; +Nsym = 8; % number of symbols to find + +% start with some LSP random vectors +% for stable filter most be monotonically increasing on 0..pi + +w_log = []; +for f=1:frames; + w = sort(rand(1,lpc_order)*pi); + w_log = [w_log; w]; +end +[w__log mse] = run_sim(sim_in, w_log); + +% sort by MSE to get the best symbols + +[sort_mse sort_ind] = sort(mse); +symbols = w_log(sort_ind(1:Nsym),:) + +% Play these symbols through the codec in random order + +w_log = []; +symb_ind = []; +for f=1:frames + symb_ind(f) = floor(1 + rand(1,1)*Nsym); + w_log = [w_log; symbols(symb_ind,:)]; +end + +[w__log mse] = run_sim(sim_in, w_log); + +% now see if we can "detect" them + +for f=1:frames + + % check received symbol against codebook of symbols + + min_e = 1E6; + for i=1:Nsym + e = w__log(f,:)*symbols(i,:)'; + if e < min_e + min_e = e; + min_ind = i; + end + end + + symb_ind_out(f) = min_ind; +end + +figure(1) +clf +plot(symb_ind,'g',symb_ind_out,'r'); diff --git a/codec2/branches/0.7/octave/ciccomp.m b/codec2/branches/0.7/octave/ciccomp.m new file mode 100644 index 00000000..936a1013 --- /dev/null +++ b/codec2/branches/0.7/octave/ciccomp.m @@ -0,0 +1,70 @@ +% ciccomp.m +% Brady O'Brien 9 Mar 2015 +% CIC Filter compensation helper + +graphics_toolkit ("gnuplot"); + +cicn = 10; %delay for CIC filter +N = 10; %input interpolation rate +csf = 256; %scaling factor for CIC filter conversion +fd = 80e3; %DAC frequency +fs = fd/N; %Input sampling frequency +fi= fd; %freq of DSP +fc1 = fi/4; %Frequency of initial upconversion +ciccb=[-0.029626 0.252638 -2.304683 16.332166 -2.304683 0.252638 -0.029626]; +%ciccb = ciccb(1:2:length(ciccb)) +t = (1:fs); + +fdin = zeros(1,length(t)); +fdin(1)=1; +fdin=fdin+sin(pi*t*(2000/fs)); +%fdin = filter(b,1,fdin); + +figure(4) +plot(20*log10(abs(fft(fdin)))) +fdcout = zeros(1,length(t)); +fdin = int64(fdin*1024); + +combout1=0; +combout2=0; +combout3=0; +%combout4=0; +ccbuf1=zeros(1,cicn/N); +ccbuf2=zeros(1,cicn/N); +ccbuf3=zeros(1,cicn/N); +%ccbuf4=zeros(1,cicn); + +for ii=1:length(fdin) + combout1 = fdin(ii) - ccbuf1(end); + combout2 = combout1 - ccbuf2(end); + combout3 = combout2 - ccbuf3(end); + %combout4 = combout3 - ccbuf4(end); + ccbuf1(2:end)=ccbuf1(1:end-1); + ccbuf2(2:end)=ccbuf2(1:end-1); + ccbuf3(2:end)=ccbuf3(1:end-1); + %ccbuf4(2:end)=ccbuf4(1:end-1); + ccbuf1(1)=fdin(ii); + ccbuf2(1)=combout1; + ccbuf3(1)=combout2; + %ccbuf4(1)=combout3; + fdcout(ii)=combout3; +end + +intout1=0; +intout2=0; +intout3=0; +%intout4=0; +fdnext = zeros(1,length(t)*N); +fdnext(1:N:length(t)*N) = fdcout; %Interpolate +fdi1 = fdnext; + +for ii=1:length(fdnext) + intout1 = fdnext(ii) + intout1; + intout2 = intout1 + intout2; + intout3 = intout2 + intout3; + %intout4 = intout3 + intout4; + fdnext(ii)=intout3; +end + +figure(5) +plot(20*log10(abs(fft(fdnext)))) diff --git a/codec2/branches/0.7/octave/cma.m b/codec2/branches/0.7/octave/cma.m new file mode 100644 index 00000000..a5a2195e --- /dev/null +++ b/codec2/branches/0.7/octave/cma.m @@ -0,0 +1,114 @@ +% cma.m +% +% Constant modulus equaliser example from: +% +% http://dsp.stackexchange.com/questions/23540/matlab-proper-estimation-of-weights-and-how-to-calculate-mse-for-qpsk-signal-f +% +% Adapted to run bpsk and fsk signals + + rand('seed',1); + randn('seed',1); + + N = 5000; % # symbols + h = [1 0 0 0 0 0 0.0 0.5]; % simulation of HF multipath channel impulse response + h = h/norm(h); + Le = 20; % equalizer length + mu = 1E-3; % step size + snr = 30; % snr in dB + M = 10; % oversample rate, e.g. Rs=400Hz at Fs=8000Hz + + tx_type = "fsk"; % select modulation type here "bpsk" or "fsk" + + if strcmp(tx_type, "bpsk") + s0 = round( rand(N,1) )*2 - 1; % BPSK signal + s0M = zeros(N*M,1); % oversampled BPSK signal + k = 1; + for i=1:M:N*M + s0M(i:i+M-1) = s0(k); + k ++; + end + end + + if strcmp(tx_type, "fsk") + tx_bits = round(rand(1,N)); + + % continuous phase FSK modulator + + w1 = pi/4; + w2 = pi/2; + tx_phase = 0; + tx = zeros(M*N,1); + + for i=1:N + for k=1:M + if tx_bits(i) + tx_phase += w2; + else + tx_phase += w1; + end + tx((i-1)*M+k) = exp(j*tx_phase); + end + end + + s0M = tx; + end + + s = filter(h,1,s0M); % filtered signal + + % add Gaussian noise at desired snr + + n = randn(N*M,1); + vs = var(s); + vn = vs*10^(-snr/10); + n = sqrt(vn)*n; + r = s + n; % received signal + + e = zeros(N*M,1); % error + w = zeros(Le,1); % equalizer coefficients + w(Le)=1; % actual filter taps are flipud(w)! + + yd = zeros(N*M,1); + + for i = 1:N*M-Le, + x = r(i:Le+i-1); + y = w'*x; + yd(i)=y; + e(i) = abs(y).^2 - 1; + w = w - mu * e(i) * real(conj(y) * x); + end + + np = 100; % # sybmols to plot (last np will be plotted); np < N! + + figure(1); clf; + %subplot(211), plot( 1:np, e(N-np+1-Le+1:N-Le+1).*e(N-np+1-Le+1:N-Le+1)), title('error') + subplot(211), plot(e.*e), title('error'); + subplot(212), stem(conv(flipud(w),h)), title('equalized channel impulse response') + + figure(2); clf; + subplot(311) + plot(1:np, s0M(N-np+1:N)) + title('transmitted, received, and equalized signal') + subplot(312) + plot(1:np, r(N-np+1:N)) + subplot(313) + plot(1:np, yd(N-np+1-Le+1:N-Le+1)) + + figure(3); clf; + h1 = freqz(h); + h2 = freqz(flipud(w)); + h3 = freqz(conv(flipud(w),h)); + subplot(311); plot(20*log10(abs(h1))); + title('channel, equaliser, combined freq resp') + subplot(312); plot(20*log10(abs(h2))); + subplot(313); plot(20*log10(abs(h3))); + + figure(4); + subplot(211) + plot(20*log10(abs(fft(s0M)))) + axis([1 length(s0M) 0 80]); + grid; + subplot(212) + plot(20*log10(abs(fft(s)))) + axis([1 length(s0M) 0 80]); + grid; + diff --git a/codec2/branches/0.7/octave/cml.patch b/codec2/branches/0.7/octave/cml.patch new file mode 100644 index 00000000..cb517a45 --- /dev/null +++ b/codec2/branches/0.7/octave/cml.patch @@ -0,0 +1,31 @@ +--- cml-orig/CmlStartup.m 2007-09-08 23:12:26.000000000 +0930 ++++ cml/CmlStartup.m 2016-09-19 10:30:08.673767127 +0930 +@@ -20,7 +20,7 @@ + addpath( strcat( cml_home, '\mex'), ... + strcat( cml_home, '\mat'), ... + strcat( cml_home, '\matalt' ), ... +- strcat( cml_home, '\mexhelp'), ... ++ %strcat( cml_home, '\mexhelp'), ... + strcat( cml_home, '\demos' ), ... + strcat( cml_home, '\scenarios'), ... + strcat( cml_home, '\localscenarios'),... +@@ -41,7 +41,7 @@ + addpath( strcat( cml_home, '/mex'), ... + strcat( cml_home, '/mat'), ... + strcat( cml_home, '/matalt' ), ... +- strcat( cml_home, '/mexhelp'), ... ++ %strcat( cml_home, '/mexhelp'), ... + strcat( cml_home, '/demos' ), ... + strcat( cml_home, '/scenarios'), ... + strcat( cml_home, '/localscenarios'),... +@@ -59,4 +59,4 @@ + save_directory = strcat( cml_home, '/scenarios/CmlHome.mat' ); + end + +-save( save_directory, save_flag, 'cml_home' ); +\ No newline at end of file ++save( save_directory, save_flag, 'cml_home' ); +--- cml-orig/source/matrix.h 1970-01-01 09:30:00.000000000 +0930 ++++ cml/source/matrix.h 2016-09-19 10:25:58.009761169 +0930 +@@ -0,0 +1 @@ ++#include diff --git a/codec2/branches/0.7/octave/codec2_demo.m b/codec2/branches/0.7/octave/codec2_demo.m new file mode 100644 index 00000000..0f3950bf --- /dev/null +++ b/codec2/branches/0.7/octave/codec2_demo.m @@ -0,0 +1,108 @@ +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% codec2_demo.m + +% Designed as an educational tool to explain the operation of Codec 2 +% for conference and user group presentations on a projector. An +% alternative to static overhead slides. +% +% Derived from codec2-dev/octave/plamp.m +% +% usage: +% octave:1> plamp("../src/hts2a",40) +% +% Then press: +% c - to cycle through the wavform being displayed on the figure +% n - next frame +% b - back one frame +% +% tip: hold down n or b to animate the display +% +% The text files used as input are generated using c2sim: +% +% /codec2-dev/src$ c2sim ../raw/hts2a.raw --dump hts2a +% +% The Codec 2 README explains how to build c2sim with dump files +% enabled. + +function codec2_demo(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + figure(1); + + k = ' '; + wf = "Sn"; + do + + if strcmp(wf,"Sn") + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s); + axis([1 length(s) -20000 20000]); + end + + if (strcmp(wf,"Sw")) + clf; + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + end + + if strcmp(wf,"SwAm") + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + hold on; + plot((1:L)*Wo*4000/pi, 20*log10(Am),"+;Am;r"); + axis([1 4000 -10 80]); + hold off; + end + + if strcmp(wf,"Am") + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Am),"+;Am;r"); + axis([1 4000 -10 80]); + end + + % interactive menu + + printf("\rframe: %d menu: n-next b-back w-cycle window q-quit", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + end + if (k == 'b') + f = f - 1; + end + if (k == 'w') + if strcmp(wf,"Sn") + next_wf = "Sw"; + end + if strcmp(wf,"Sw") + next_wf = "SwAm"; + end + if strcmp(wf,"SwAm") + next_wf = "Am"; + end + if strcmp(wf,"Am") + next_wf = "Sn"; + end + wf = next_wf; + end + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/cohpsk.m b/codec2/branches/0.7/octave/cohpsk.m new file mode 100644 index 00000000..34abfa7d --- /dev/null +++ b/codec2/branches/0.7/octave/cohpsk.m @@ -0,0 +1,992 @@ +% cohpsk.m +% David Rowe Mar 2015 +% +% Coherent PSK modem functions, with support for LDPC and DSSS +% (diversity). + +1; + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +% init function for symbol rate processing -------------------------------------------------------- + +function sim_in = symbol_rate_init(sim_in) + sim_in.Fs = Fs = 8000; + + modulation = sim_in.modulation; + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + + Rs = sim_in.Rs; + Nc = sim_in.Nc; + + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + + Nd = sim_in.Nd; % diveristy + Ns = sim_in.Ns; % step size between pilots + ldpc_code = sim_in.ldpc_code; + rate = sim_in.ldpc_code_rate; + + sim_in.bps = bps = 2; + + sim_in.Nsymb = Nsymb = framesize/bps; + sim_in.Nsymbrow = Nsymbrow = Nsymb/Nc; + sim_in.Npilotsframe = Npilotsframe = 2; + sim_in.Nsymbrowpilot = Nsymbrowpilot = Nsymbrow + Npilotsframe; + + if verbose == 2 + printf("Each frame contains %d data bits or %d data symbols, transmitted as %d symbols by %d carriers.", framesize, Nsymb, Nsymbrow, Nc); + printf(" There are %d pilot symbols in each carrier together at the start of each frame, then %d data symbols.", Npilotsframe, Ns); + printf(" Including pilots, the frame is %d symbols long by %d carriers.\n\n", Nsymbrowpilot, Nc); + end + + sim_in.prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc*Nd); + sim_in.prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc*Nd); + + sim_in.rx_symb_buf = zeros(3*Nsymbrow, Nc*Nd); + sim_in.rx_pilot_buf = zeros(3*Npilotsframe,Nc*Nd); + sim_in.tx_bits_buf = zeros(1,2*framesize); + + % pilot sequence is used for phase and amplitude estimation, and frame sync + + pilot = 1 - 2*(rand(Npilotsframe,Nc) > 0.5); + sim_in.pilot = pilot; + sim_in.tx_pilot_buf = [pilot; pilot; pilot]; + if sim_in.do_write_pilot_file + write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymbrow, Npilotsframe, Nc); + end + + % we use first 2 pilots of next frame to help with frame sync and fine freq + + sim_in.Nct_sym_buf = 2*Nsymbrowpilot + 2; + sim_in.ct_symb_buf = zeros(sim_in.Nct_sym_buf, Nc*Nd); + + sim_in.ff_phase = 1; + + sim_in.ct_symb_ff_buf = zeros(Nsymbrowpilot + 2, Nc*Nd); + + % Init LDPC -------------------------------------------------------------------- + + if ldpc_code + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + mod_order = 4; + modulation2 = 'QPSK'; + mapping = 'gray'; + + sim_in.demod_type = 0; + sim_in.decoder_type = 0; + sim_in.max_iterations = 100; + + code_param = ldpc_init(rate, framesize, modulation2, mod_order, mapping); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/bps; + sim_in.code_param = code_param; + else + sim_in.rate = 1; + sim_in.code_param = []; + end +endfunction + + +% Symbol rate processing for tx side (modulator) ------------------------------------------------------- + +% legacy DQPSK mod for comparative testing + +function [tx_symb prev_tx_symb] = bits_to_dqpsk_symbols(sim_in, tx_bits, prev_tx_symb) + Nc = sim_in.Nc; + Nsymbrow = sim_in.Nsymbrow; + + tx_symb = zeros(Nsymbrow,Nc); + + for c=1:Nc + for r=1:Nsymbrow + i = (c-1)*Nsymbrow + r; + tx_symb(r,c) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + tx_symb(r,c) *= prev_tx_symb(c); + prev_tx_symb(c) = tx_symb(r,c); + end + end + +endfunction + + +% legacy DQPSK demod for comparative testing + +function [rx_symb rx_bits rx_symb_linear prev_rx_symb] = dqpsk_symbols_to_bits(sim_in, rx_symb, prev_rx_symb) + Nc = sim_in.Nc; + Nsymbrow = sim_in.Nsymbrow; + + tx_symb = zeros(Nsymbrow,Nc); + + for c=1:Nc + for r=1:Nsymbrow + tmp = rx_symb(r,c); + rx_symb(r,c) *= conj(prev_rx_symb(c))/abs(prev_rx_symb(c)); + prev_rx_symb(c) = tmp; + i = (c-1)*Nsymbrow + r; + rx_symb_linear(i) = rx_symb(r,c); + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb(r,c)); + end + end + +endfunction + + +function [tx_symb tx_bits] = bits_to_qpsk_symbols(sim_in, tx_bits, code_param) + ldpc_code = sim_in.ldpc_code; + rate = sim_in.ldpc_code_rate; + framesize = sim_in.framesize; + Nsymbrow = sim_in.Nsymbrow; + Nsymbrowpilot = sim_in.Nsymbrowpilot; + Nc = sim_in.Nc; + Npilotsframe = sim_in.Npilotsframe; + Ns = sim_in.Ns; + modulation = sim_in.modulation; + pilot = sim_in.pilot; + Nd = sim_in.Nd; + + if ldpc_code + [tx_bits, tmp] = ldpc_enc(tx_bits, code_param); + end + + % modulate -------------------------------------------- + + % organise symbols into a Nsymbrow rows by Nc cols + % data and parity bits are on separate carriers + + tx_symb = zeros(Nsymbrow,Nc); + + for c=1:Nc + for r=1:Nsymbrow + i = (c-1)*Nsymbrow + r; + tx_symb(r,c) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + end + end + + % insert pilots at start of frame + + tx_symb = [pilot(1,:); pilot(2,:); tx_symb;]; + + % copy to other carriers (diversity) + + tmp = tx_symb; + for d=1:Nd-1 + tmp = [tmp tx_symb]; + end + tx_symb = tmp; + + % ensures energy/symbol is normalised with diversity + + tx_symb = tx_symb/sqrt(Nd); +end + + +% Symbol rate processing for rx side (demodulator) ------------------------------------------------------- + +function [rx_symb rx_bits rx_symb_linear amp_ phi_ sig_rms noise_rms cohpsk] = qpsk_symbols_to_bits(cohpsk, ct_symb_buf) + framesize = cohpsk.framesize; + Nsymb = cohpsk.Nsymb; + Nsymbrow = cohpsk.Nsymbrow; + Nsymbrowpilot = cohpsk.Nsymbrowpilot; + Nc = cohpsk.Nc; + Nd = cohpsk.Nd; + Npilotsframe = cohpsk.Npilotsframe; + pilot = cohpsk.pilot; + verbose = cohpsk.verbose; + coh_en = cohpsk.coh_en; + + % Use pilots to get phase and amplitude estimates We assume there + % are two samples at the start of each frame and two at the end + % Note: correlation (averging) method was used initially, but was + % poor at tracking fast phase changes that we experience on fading + % channels. Linear regression (fitting a straight line) works + % better on fading channels, but increases BER slighlty for AWGN + % channels. + + sampling_points = [1 2 cohpsk.Nsymbrow+3 cohpsk.Nsymbrow+4]; + pilot2 = [cohpsk.pilot(1,:); cohpsk.pilot(2,:); cohpsk.pilot(1,:); cohpsk.pilot(2,:);]; + phi_ = zeros(Nsymbrow, Nc*Nd); + amp_ = zeros(Nsymbrow, Nc*Nd); + + for c=1:Nc*Nd + %corr = pilot2(:,c)' * ct_symb_buf(sampling_points,c); + %phi_(:, c) = angle(corr); + + y = ct_symb_buf(sampling_points,c) .* pilot2(:,c-Nc*floor((c-1)/Nc)); + [m b] = linreg(sampling_points, y, length(sampling_points)); + yfit = m*[3 4 5 6] + b; + phi_(:, c) = angle(yfit); + %for r=1:Nsymbrow + % printf(" %f", phi_(r,c)); + %end + %printf("\n"); + mag = sum(abs(ct_symb_buf(sampling_points,c))); + amp_(:, c) = mag/length(sampling_points); + end + + % now correct phase of data symbols + + rx_symb = zeros(Nsymbrow, Nc); + rx_symb_linear = zeros(1, Nsymbrow*Nc*Nd); + rx_bits = zeros(1, framesize); + for c=1:Nc*Nd + for r=1:Nsymbrow + if coh_en == 1 + rx_symb(r,c) = ct_symb_buf(2+r,c)*exp(-j*phi_(r,c)); + else + rx_symb(r,c) = ct_symb_buf(2+r,c); + end + i = (c-1)*Nsymbrow + r; + rx_symb_linear(i) = rx_symb(r,c); + %printf("phi_ %d %d %f %f\n", r,c,real(exp(-j*phi_(r,c))), imag(exp(-j*phi_(r,c)))); + end + end + + % and finally optional diversity combination and make decn on bits + + for c=1:Nc + for r=1:Nsymbrow + i = (c-1)*Nsymbrow + r; + div_symb = rx_symb(r,c); + for d=1:Nd-1 + div_symb += rx_symb(r,c + Nc*d); + end + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(div_symb); + end + end + + % Estimate noise power from demodulated symbols. One method is to + % calculate the distance of each symbol from the average symbol + % position. However this is complicated by fading, which means the + % amplitude of the symbols is constantly changing. + + % Now the scatter diagram in a fading channel is a X or cross + % shape. The noise can be resolved into two components at right + % angles to each other. The component along the the "thickness" + % of the arms is proportional to the noise power and not affected + % by fading. We only use points further along the real axis than + % the mean amplitude so we keep out of the central nosiey blob + + sig_rms = mean(abs(rx_symb_linear)); + + sum_x = 0; + sum_xx = 0; + n = 0; + for i=1:Nsymb*Nd + s = rx_symb_linear(i); + if abs(real(s)) > sig_rms + sum_x += imag(s); + sum_xx += imag(s)*imag(s); + n++; + end + end + + noise_var = 0; + if n > 1 + noise_var = (n*sum_xx - sum_x*sum_x)/(n*(n-1)); + end + noise_rms = sqrt(noise_var); + +endfunction + + +% Compression, John Gibbs pointed out it's best to perform non-linear +% operations on an oversampled signals as they tend to generate +% broadband noise that will be aliased into passband if bandwidth is +% too low + +function y = compress(x, power) + + % oversample by a factor of M + + M = 4; + Ntap = 47; + n = length(x); + + b = fir1(Ntap,1/M); + xM = zeros(1,M*n); + for i=1:n + xM(i*M) = M*x(i); + end + + xM = filter(b,1,xM); + + % non linearity + + yM = sign(xM).*(abs(xM) .^ power); + + % decimate by a factor of M + + yM = filter(b,1,yM); + y = yM(1:M:n*M); + +endfunction + + +% Init HF channel model from stored sample files of spreading signal ---------------------------------- + +function [spread spread_2ms hf_gain] = init_hf_model(Fs, nsam) + + % convert "spreading" samples from 1kHz carrier at Fss to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; Fss = 8000; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fss)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fss)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fss); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % change output samples so they are at rate Fs reqd by caller + + spread = resample(spread, Fs, Fss); + spread_2ms = resample(spread_2ms, Fs, Fss); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread(1:nsam))+var(spread_2ms(1:nsam))); +endfunction + + +function write_pilot_file(pilot, Nsymbrowpilot, Ns, Nsymrow, Npilotsframe, Nc); + + filename = sprintf("../src/cohpsk_defs.h", Npilotsframe, Nc); + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n"); + fprintf(f,"#define NSYMROW %d /* number of data symbols on each row (i.e. each carrier) */\n", Nsymrow); + fprintf(f,"#define NS %d /* number of data symbols between pilots */\n", Ns); + fprintf(f,"#define NPILOTSFRAME %d /* number of pilot symbols on each row */\n", Npilotsframe); + fprintf(f,"#define PILOTS_NC %d /* number of carriers */\n\n", Nc); + fprintf(f,"#define NSYMROWPILOT %d /* length of row after pilots inserted */\n\n", Nsymbrowpilot); + fclose(f); + + filename = sprintf("../src/pilots_coh.h", Npilotsframe, Nc); + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by write_pilot_file() Octave function */\n\n"); + fprintf(f,"float pilots_coh[][PILOTS_NC]={\n"); + for r=1:Npilotsframe + fprintf(f, " {"); + for c=1:Nc-1 + fprintf(f, " %f,", pilot(r, c)); + end + if r < Npilotsframe + fprintf(f, " %f},\n", pilot(r, Nc)); + else + fprintf(f, " %f}\n};", pilot(r, Nc)); + end + end + fclose(f); +endfunction + + +% Save test bits frame to a text file in the form of a C array + +function test_bits_coh_file(test_bits_coh) + + f=fopen("../src/test_bits_coh.h","wt"); + fprintf(f,"/* Generated by test_bits_coh_file() Octave function */\n\n"); + fprintf(f,"const int test_bits_coh[]={\n"); + for m=1:length(test_bits_coh)-1 + fprintf(f," %d,\n",test_bits_coh(m)); + endfor + fprintf(f," %d\n};\n",test_bits_coh(length(test_bits_coh))); + fclose(f); + +endfunction + + +function [ch_symb rx_timing rx_filt rx_baseband afdmdv f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame, f_est, nsymb, nin, freq_track) + M = afdmdv.M; + + rx_baseband = []; + rx_filt = []; + rx_timing = []; + + ch_fdm_frame_index = 1; + + for r=1:nsymb + % shift signal to nominal baseband, this will put Nc/2 carriers either side of 0 Hz + + [rx_fdm_frame_bb afdmdv.fbb_phase_rx] = freq_shift(ch_fdm_frame(ch_fdm_frame_index:ch_fdm_frame_index + nin - 1), -f_est, afdmdv.Fs, afdmdv.fbb_phase_rx); + ch_fdm_frame_index += nin; + + % downconvert each FDM carrier to Nc separate baseband signals + + [arx_baseband afdmdv] = fdm_downconvert(afdmdv, rx_fdm_frame_bb, nin); + [arx_filt afdmdv] = rx_filter(afdmdv, arx_baseband, nin); + [rx_onesym arx_timing env afdmdv] = rx_est_timing(afdmdv, arx_filt, nin); + + rx_baseband = [rx_baseband arx_baseband]; + rx_filt = [rx_filt arx_filt]; + rx_timing = [rx_timing arx_timing]; + + ch_symb(r,:) = rx_onesym; + + % we only allow a timing shift on one symbol per frame + + if nin != M + nin = M; + end + + % freq tracking, see test_ftrack.m for unit test. Placed in + % this function as it needs to work on a symbol by symbol basis + % rather than frame by frame. This means the control loop + % operates at a sample rate of Rs = 50Hz for say 1 Hz/s drift. + + if freq_track + beta = 0.005; + g = 0.2; + + % combine difference on phase from last symbol over Nc carriers + + mod_strip = 0; + for c=1:afdmdv.Nc+1 + adiff = rx_onesym(c) .* conj(afdmdv.prev_rx_symb(c)); + afdmdv.prev_rx_symb(c) = rx_onesym(c); + + % 4th power strips QPSK modulation, by multiplying phase by 4 + % Using the abs value of the real coord was found to help + % non-linear issues when noise power was large + + amod_strip = adiff.^4; + amod_strip = abs(real(amod_strip)) + j*imag(amod_strip); + mod_strip += amod_strip; + end + %plot(mod_strip) + %printf("modstrip: %f %f\n", real(mod_strip), imag(mod_strip)); + + % loop filter made up of 1st order IIR plus integrator. Integerator + % was found to be reqd + + afdmdv.filt = (1-beta)*afdmdv.filt + beta*angle(mod_strip); + f_est += g*afdmdv.filt; + %printf("filt: %f angle: %f\n", afdmdv.filt, angle(mod_strip)); + + end + end +endfunction + + +function ct_symb_buf = update_ct_symb_buf(ct_symb_buf, ch_symb, Nct_sym_buf, Nsymbrowpilot) + + % update memory in symbol buffer + + for r=1:Nct_sym_buf-Nsymbrowpilot + ct_symb_buf(r,:) = ct_symb_buf(r+Nsymbrowpilot,:); + end + i = 1; + for r=Nct_sym_buf-Nsymbrowpilot+1:Nct_sym_buf + ct_symb_buf(r,:) = ch_symb(i,:); + i++; + end +endfunction + + +% returns index of start of frame and fine freq offset + +function [next_sync cohpsk] = frame_sync_fine_freq_est(cohpsk, ch_symb, sync, next_sync) + ct_symb_buf = cohpsk.ct_symb_buf; + Nct_sym_buf = cohpsk.Nct_sym_buf; + Rs = cohpsk.Rs; + Nsymbrowpilot = cohpsk.Nsymbrowpilot; + Nc = cohpsk.Nc; + Nd = cohpsk.Nd; + + ct_symb_buf = update_ct_symb_buf(ct_symb_buf, ch_symb, Nct_sym_buf, Nsymbrowpilot); + cohpsk.ct_symb_buf = ct_symb_buf; + + % sample pilots at start of this frame and start of next frame + + sampling_points = [1 2 cohpsk.Nsymbrow+3 cohpsk.Nsymbrow+4]; + pilot2 = [ cohpsk.pilot(1,:); cohpsk.pilot(2,:); cohpsk.pilot(1,:); cohpsk.pilot(2,:);]; + + if sync == 0 + + % sample correlation over 2D grid of time and fine freq points + + max_corr = 0; + for f_fine=-20:0.25:20 +% for f_fine=-1:0.25:1 + f_fine_rect = exp(-j*f_fine*2*pi*sampling_points/Rs)'; % note: this could be pre-computed at init or compile time + for t=0:cohpsk.Nsymbrowpilot-1 + corr = 0; mag = 0; + for c=1:Nc*Nd + f_corr_vec = f_fine_rect .* ct_symb_buf(t+sampling_points,c); % note: this could be pre-computed at init or compile time + acorr = 0.0; + for p=1:length(sampling_points) + acorr += pilot2(p,c-Nc*floor((c-1)/Nc)) * f_corr_vec(p); + mag += abs(f_corr_vec(p)); + end + corr += abs(acorr); + end + %printf(" f: %f t: %d corr: %f mag: %f ratio: %f\n", f_fine, t, corr, mag, corr/mag); + if corr >= max_corr + max_corr = corr; + max_mag = mag; + cohpsk.ct = t; + cohpsk.f_fine_est = f_fine; + cohpsk.ff_rect = exp(-j*f_fine*2*pi/Rs); + end + end + end + + printf(" [%d] fine freq f: %f max_ratio: %f ct: %d\n", cohpsk.frame, cohpsk.f_fine_est, abs(max_corr)/max_mag, cohpsk.ct); + if abs(max_corr/max_mag) > 0.9 + printf(" [%d] encouraging sync word! ratio: %f\n", cohpsk.frame, abs(max_corr/max_mag)); + cohpsk.sync_timer = 0; + next_sync = 1; + else + next_sync = 0; + %printf(" [%d] back to coarse freq offset est...\n", cohpsk.frame) ; + end + cohpsk.ratio = abs(max_corr/max_mag); + end + + % single point correlation just to see if we are still in sync + + if sync == 1 + corr = 0; mag = 0; + f_fine_rect = exp(-j*cohpsk.f_fine_est*2*pi*sampling_points/Rs)'; + for c=1:Nc*Nd + f_corr_vec = f_fine_rect .* ct_symb_buf(cohpsk.ct+sampling_points,c); + acorr = 0; + for p=1:length(sampling_points) + acorr += pilot2(p, c-Nc*floor((c-1)/Nc)) * f_corr_vec(p); + mag += abs(f_corr_vec(p)); + end + corr += abs(acorr); + end + cohpsk.ratio = abs(corr)/mag; + %printf("f_fine_est: %f ratio: %f\n", cohpsk.f_fine_est, cohpsk.ratio); + end + +endfunction + + +% misc sync state machine code, just wanted it in a function + +function [sync cohpsk] = sync_state_machine(cohpsk, sync, next_sync) + + if sync == 1 + + % check that sync is still good, fall out of sync on consecutive bad frames */ + + if cohpsk.ratio < 0.8 + cohpsk.sync_timer++; + else + cohpsk.sync_timer = 0; + end + % printf(" ratio: %f sync timer: %d\n", cohpsk.ratio, cohpsk.sync_timer); + + if cohpsk.sync_timer == 10 + printf(" [%d] lost sync ....\n", cohpsk.frame); + next_sync = 0; + end + end + + sync = next_sync; +endfunction + + +% Rate Rs BER tests ------------------------------------------------------------------------------ + +function sim_out = ber_test(sim_in) + sim_in = symbol_rate_init(sim_in); + + Fs = sim_in.Fs; + Rs = sim_in.Rs; + Ntrials = sim_in.Ntrials; + verbose = sim_in.verbose; + plot_scatter = sim_in.plot_scatter; + framesize = sim_in.framesize; + bps = sim_in.bps; + + Esvec = sim_in.Esvec; + ldpc_code = sim_in.ldpc_code; + rate = sim_in.ldpc_code_rate; + code_param = sim_in.code_param; + tx_bits_buf = sim_in.tx_bits_buf; + Nsymb = sim_in.Nsymb; + Nsymbrow = sim_in.Nsymbrow; + Nsymbrowpilot = sim_in.Nsymbrowpilot; + Nc = sim_in.Nc; + Npilotsframe = sim_in.Npilotsframe; + Ns = sim_in.Ns; + Np = sim_in.Np; + Nd = sim_in.Nd; + modulation = sim_in.modulation; + pilot = sim_in.pilot; + prev_sym_tx = sim_in.prev_sym_tx; + prev_sym_rx = sim_in.prev_sym_rx; + rx_symb_buf = sim_in.rx_symb_buf; + tx_pilot_buf = sim_in.tx_pilot_buf; + rx_pilot_buf = sim_in.rx_pilot_buf; + + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + f_off = sim_in.f_off; + div_time_shift = sim_in.div_timeshift; + + [spread spread_2ms hf_gain] = init_hf_model(Rs, Nsymbrowpilot*(Ntrials+2)); + + if strcmp(modulation,'dqpsk') + Nsymbrowpilot = Nsymbrow; + end + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + s_ch_tx_log = []; + rx_symb_log = []; + noise_log = []; + errors_log = []; + Nerrs_log = []; + phi_log = []; + amp_log = []; + EsNo__log = []; + + ldpc_errors_log = []; ldpc_Nerrs_log = []; + + Terrsldpc = Tbitsldpc = Ferrsldpc = 0; + + % init HF channel + + hf_n = 1; + + phase_offset_rect = 1; + w_offset = 2*pi*f_off/Rs; + w_offset_rect = exp(j*w_offset); + + ct_symb_buf = zeros(2*Nsymbrowpilot, Nc*Nd); + prev_tx_symb = prev_rx_symb = ones(1, Nc*Nd); + + % simulation starts here----------------------------------- + + for nn = 1:Ntrials+2 + + if ldpc_code + tx_bits = round(rand(1,framesize*rate)); + else + tx_bits = round(rand(1,framesize)); + end + + if strcmp(modulation,'qpsk') + + [tx_symb tx_bits] = bits_to_qpsk_symbols(sim_in, tx_bits, code_param); + + % one frame delay on bits for qpsk + + tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize); + tx_bits_buf(framesize+1:2*framesize) = tx_bits; + + end + if strcmp(modulation, 'dqpsk') + [tx_symb prev_tx_symb] = bits_to_dqpsk_symbols(sim_in, tx_bits, prev_tx_symb); + tx_bits_buf(1:framesize) = tx_bits; + end + + s_ch = tx_symb; + + % HF channel simulation ------------------------------------ + + hf_fading = ones(1,Nsymb); + if hf_sim + + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + hf_model(hf_n, :) = zeros(1,Nc*Nd); + + for r=1:Nsymbrowpilot + for c=1:Nd*Nc + if c > Nc + time_shift = sim_in.div_timeshift; + else + time_shift = 1; + end + ahf_model = hf_gain*(spread(hf_n+time_shift) + exp(-j*c*wsep*nhfdelay)*spread_2ms(hf_n+time_shift)); + + if hf_mag_only + s_ch(r,c) *= abs(ahf_model); + else + s_ch(r,c) *= ahf_model; + end + hf_model(hf_n, c) = ahf_model; + end + hf_n++; + end + end + + % keep a record of each tx symbol so we can check average power + + for r=1:Nsymbrow + for c=1:Nd*Nc + s_ch_tx_log = [s_ch_tx_log s_ch(r,c)]; + end + end + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(Nsymbrowpilot,Nc*Nd) + j*randn(Nsymbrowpilot,Nc*Nd)); + noise_log = [noise_log noise]; + + for r=1:Nsymbrowpilot + s_ch(r,:) *= phase_offset_rect; + phase_offset_rect *= w_offset_rect; + end + s_ch += noise; + + ct_symb_buf(1:Nsymbrowpilot,:) = ct_symb_buf(Nsymbrowpilot+1:2*Nsymbrowpilot,:); + ct_symb_buf(Nsymbrowpilot+1:2*Nsymbrowpilot,:) = s_ch; + + if strcmp(modulation,'qpsk') + [rx_symb rx_bits rx_symb_linear amp_ phi_ EsNo_ sim_in] = qpsk_symbols_to_bits(sim_in, ct_symb_buf(1:Nsymbrowpilot+Npilotsframe,:)); + phi_log = [phi_log; phi_]; + amp_log = [amp_log; amp_]; + end + if strcmp(modulation,'dqpsk') + [rx_symb rx_bits rx_symb_linear prev_rx_symb] = dqpsk_symbols_to_bits(sim_in, s_ch, prev_rx_symb); + end + + % Wait until we have enough frames to do pilot assisted phase estimation + + if nn > 1 + rx_symb_log = [rx_symb_log rx_symb_linear]; + %EsNo__log = [EsNo__log EsNo_]; + + % Measure BER + + error_positions = xor(rx_bits, tx_bits_buf(1:framesize)); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + + % Optionally LDPC decode + + if ldpc_code + detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ... + rx_symb_linear, min(100,EsNo_), amp_linear); + error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) ); + Nerrs = sum(error_positions); + ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs]; + ldpc_errors_log = [ldpc_errors_log error_positions]; + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + end + end + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + av_tx_pwr = (s_ch_tx_log * s_ch_tx_log')/length(s_ch_tx_log); + + printf("EsNo (dB): %3.1f Terrs: %d Tbits: %d BER %5.3f QPSK BER theory %5.3f av_tx_pwr: %3.2f", + EsNodB, Terrs, Tbits, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + if ldpc_code + printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials); + end + printf("\n"); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + sim_out.ldpc_errors_log = ldpc_errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + a = 1.5*max(real(scat)); b = 1.5*max(imag(scat)); + axis([-a a -b b]); + + if hf_sim + figure(3); + clf; + + y = 1:(hf_n-1); + x = 1:Nc*Nd; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + EsNodBSurface(find(EsNodBSurface > 25)) = 25; + mesh(x,y,EsNodBSurface); + grid + axis([1 Nc*Nd 1 Rs*5 -5 25]) + title('HF Channel Es/No'); + + if verbose + [m n] = size(hf_model); + av_hf_pwr = sum(sum(abs(hf_model(:,:)).^2))/(m*n); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, m*n); + end + + end + + if strcmp(modulation,'qpsk') + % set up time axis to include gaps for pilots + + [m1 n1] = size(phi_log); + phi_x = []; + phi_x_counter = 1; + p = Ns; + for r=1:m1 + if p == Ns + phi_x_counter += Npilotsframe; + p = 0; + end + p++; + phi_x = [phi_x phi_x_counter++]; + end + + phi_x -= Nsymbrowpilot; % account for delay in pilot buffer + + figure(5); + clf + subplot(211) + [m n] = size(phi_log); + plot(phi_x, phi_log(:,2),'r+;Estimated HF channel phase;') + if hf_sim + hold on; + [m n] = size(hf_model); + plot(angle(hf_model(1:m,2)),'g;HF channel phase;') + hold off; + end + ylabel('Phase (rads)'); + legend('boxoff'); + axis([1 m -1.1*pi 1.1*pi]) + + subplot(212) + plot(phi_x, amp_log(:,2),'r+;Estimated HF channel amp;') + if hf_sim + hold on; + plot(abs(hf_model(1:m,2))) + hold off; + end + ylabel('Amplitude'); + xlabel('Time (symbols)'); + legend('boxoff'); + axis([1 m 0 3]) + end + + figure(4) + clf + stem(Nerrs_log) + axis([1 length(Nerrs_log) 0 max(Nerrs_log)+1]) + end + +endfunction + + + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.do_write_pilot_file = 0; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 50; + sim_in.Ntrials = 30; + sim_in.framesize = 2; + sim_in.Rs = 50; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; + + sim_in.Nd = 1; +endfunction diff --git a/codec2/branches/0.7/octave/cohpsk_demod_plot.m b/codec2/branches/0.7/octave/cohpsk_demod_plot.m new file mode 100644 index 00000000..44376bac --- /dev/null +++ b/codec2/branches/0.7/octave/cohpsk_demod_plot.m @@ -0,0 +1,159 @@ +% cohpsk_demod_plot.m +% David Rowe May 2015 +% +% Plot Octave outputs from cohpsk_demod, c2dec, to visualise whats going on +% when errors hit the system + +% $ ./c2enc 700 ../../raw/ve9qrp_10s.raw - | ./cohpsk_mod - - | ./cohpsk_ch - - -60 50 1 1 | ./cohpsk_demod - - cohpsk_demod.txt | ./c2dec 700 - - --dump ve9qrp | play -t raw -r 8000 -s -2 - -q + +% ./c2enc 700 ../../raw/ve9qrp_10s.raw - | ./cohpsk_mod - - | ./cohpsk_ch - - -30 50 1 1 | ./cohpsk_demod - - cohpsk_demod.txt | ./c2dec 700 - - --dump ve9qrp_snr3 | play -t raw -r 8000 -s -2 - -q + +graphics_toolkit ("gnuplot"); + +Nc=7; Nd=2; Ns=6; + +load ../build_linux/src/cohpsk_demod.txt +load ../build_linux/src/cohpsk_put_test_bits.txt +load ../build_linux/src/ve9qrp_lsp_.txt +load ../build_linux/src/ve9qrp_snr3_lsp_.txt +load ../build_linux/src/ve9qrp_ak_.txt +load ../build_linux/src/ve9qrp_snr3_ak_.txt +load ../build_linux/src/ve9qrp_model.txt +load ../build_linux/src/ve9qrp_snr3_model.txt +load ../build_linux/src/ve9qrp_snr3_softdec.txt + +Ncf = 50; % number of codec frames to plot +Nmf = Ncf/2; % number of modem frames to plot +Nms = Nmf*Ns; % number of modem symbols to plot + +figure(1) +clf; + +% plot combined signals to show diversity gains + +combined = rx_symb_log_c(:,1:Nc); +for d=2:Nd + combined += rx_symb_log_c(:, (d-1)*Nc+1:d*Nc); +end +plot(combined*exp(j*pi/4)/sqrt(Nd),'+') +title('Scatter'); +axis([-2 2 -2 2]) + +figure(2) +clf; +subplot(211) +plot(rx_phi_log_c(1:Nms,:)) +title('phase') +axis([1 Nms -pi pi]) +subplot(212) +plot(rx_amp_log_c(1:Nms,:)) +title('amplitude') +axis([1 Nms 0 1]) + +figure(3) +subplot(211) +plot(rx_timing_log_c) +title('rx timing'); +subplot(212) +stem(ratio_log_c) +title('Sync ratio'); + +figure(4); +clf; +plot(nerr_log_c(1:Ncf)); +title('Bit Errors'); +xlabel('Codec Frame') + +figure(5); +clf; +plot(error_positions_hist_c); +title('Error Position Histogram'); + +figure(6) +y = 1:Nms; +x = 1:Nc*Nd; +z = 20*log10(rx_amp_log_c(1:Nms,:)); +mesh(x,y,z); +grid +title('Channel Amplitude dB'); +a = min(min(z)); +b = max(max(z)); +axis([1 Nc*Nd 1 Nms a b]) + +% work out alignment, as they sync at different times + +min_e = 1E6; +for i=1:10 + l1 = length(ve9qrp_lsp_); + l2 = length(ve9qrp_snr3_lsp_); + st = i; en = min(l1+i-1,l2); + d = ve9qrp_lsp_(st:en, 1:6) - ve9qrp_snr3_lsp_(1:en-st+1, 1:6); + e = sum(sum(abs(d))); + if e < min_e + min_e = e; + min_i = i; + end +end +printf("time offset between clean and 3dB is %d codec frames\n", min_i); + +% LSP trajectories + +figure(7) +clf +st = min_i; en = 50; +plot(ve9qrp_snr3_lsp_(1:en-st+1, 1:6),'r--') +hold on +plot(ve9qrp_lsp_(st:en, 1:6),'g') +hold off + +% Spectral distortion of LPCs + +figure(8) +clf; +f1=1./fft(ve9qrp_ak_(st:en,:)',128); +f2=1./fft(ve9qrp_snr3_ak_(1:en-st+1,:)',128); +%d = (20*log10(abs(f1)) - 20*log10(abs(f2))); +d = 20*log10(abs(f2)); +sdsq = mean(d.^2); +plot(sdsq) +title('spectral distortion clean and channel SNR=3dB') + +figure(9) +clf; +y = 1:en-st+1; +x = 1:40; +%mesh(y,x,-20*log10(abs(f2(1:40,:)))); +mesh(y,x,d(x,:)); +grid +title('Synthesis filter difference between clean and channel SNR=3dB'); +xlabel('Time (codec frames)') +ylabel('Frequency 0 to 2500Hz'); +zlabel('Difference (dB)'); + +% map soft decn information to LSPs + +mel1 = ve9qrp_snr3_softdec(:,10:12); +mel2 = ve9qrp_snr3_softdec(:,13:14); +mel3 = ve9qrp_snr3_softdec(:,15:18); +mel4 = ve9qrp_snr3_softdec(:,19:21); +mel5 = ve9qrp_snr3_softdec(:,22:24); +mel6 = ve9qrp_snr3_softdec(:,25:26); +softdec_mel = [sum(mel1'.^2); sum(mel2'.^2); sum(mel3'.^2); sum(mel4'.^2); sum(mel5'.^2); sum(mel6'.^2)]; + +figure(10) +clf; +y = 1:en-st+1; +x = 1:6; +%mesh(y,x,-20*log10(abs(f2(1:40,:)))); +mesh(y, x, softdec_mel(:,y)); +grid +xlabel('Codec frame') +ylabel('LSP') +zlabel('Power') +%axis([1 (en-st+1) 1 6 -10 5]) + +% plot symbol energy against SD + +figure(11) +semilogx(mean(softdec_mel(:,1:en-st+1)), sdsq,'+') +grid diff --git a/codec2/branches/0.7/octave/cohpsk_frame_design.ods b/codec2/branches/0.7/octave/cohpsk_frame_design.ods new file mode 100644 index 0000000000000000000000000000000000000000..915ea08f50e284fe14e3587a5f6309d806758c6b GIT binary patch literal 49734 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/octave/cohpsk_plots.m b/codec2/branches/0.7/octave/cohpsk_plots.m new file mode 100644 index 00000000..9fc9a11f --- /dev/null +++ b/codec2/branches/0.7/octave/cohpsk_plots.m @@ -0,0 +1,141 @@ +% cohpsk_plots.m +% David Rowe Feb 2017 +% +% Generate some plots for chps modem blog post + +rand("seed",1); + +% Multipath with simple unfiltered BPSK signal + +N = 100; % number of symbols +M = 4; % oversample rate + +tx_bits = rand(1,N) > 0.5; +tx_symbols = 2*tx_bits - 1; +tx = zeros(1,N*M); + +for i=1:N + tx((i-1)*M+1:i*M) = tx_symbols(i); +end + +h = [0 0 0 0 0.5]; % model of second path + +rx1 = tx; +rx2 = filter(h,1,tx); +rx = rx1 + rx2; + +% Multipath in time domain + +figure(1); clf; +subplot(311) +plot(rx1, "linewidth", 4) +axis([0 10*M+1 -2 2]); +subplot(312) +plot(rx2, "linewidth", 4) +axis([0 10*M+1 -2 2]); +subplot(313) +plot(rx, "linewidth", 4) +axis([0 10*M+1 -2 2]); +xlabel('Time'); +print("cohpsk_multipath_time.png", "-dpng", "-S600,440", "-F:8") + +% Multipath channel magnitude and phase response against frequency + +h = [1 0 0 0 0.5]; % model of two path multipath channel +H = freqz(h,1,100); + +figure(2); clf; +subplot(211) +plot(20*log10(abs(H)), "linewidth", 4) +title('Amplitude (dB)'); +subplot(212) +plot(angle(H), "linewidth", 4) +title('Phase (rads)'); +%axis([0 500 -2 2]); +xlabel('Frequency'); +print("cohpsk_multipath_channel.png", "-dpng", "-S600,440", "-F:8") + +% Effective of 1 sample multipath for different symbols lengths + +h = [1 0 0 0 0.5]; % model of two path multipath channel +M1 = 2; +M2 = 20; +tx1 = zeros(1,N*M1); +tx2 = zeros(1,N*M2); +for i=1:N + tx1((i-1)*M1+1:i*M1) = tx_symbols(i); + tx2((i-1)*M2+1:i*M2) = tx_symbols(i); +end + +rx1 = filter(h,1,tx1); +rx2 = filter(h,1,tx2); + +figure(3); clf; +subplot(211) +plot(rx1, "linewidth", 4) +axis([0 10*M1+1 -2 2]); +title('1ms multipath with 2ms symbols') +subplot(212) +plot(rx2, "linewidth", 4) +axis([0 10*M2+1 -2 2]); +title('1ms multipath with 20ms symbols') +xlabel('Time'); +print("cohpsk_multipath_symbol_length.png", "-dpng", "-S600,440", "-F:8") + +% DBPSK -------------------------------------------------- + +N = 10; +tx_bits = rand(1,N) > 0.5; +bpsk = 2*tx_bits - 1; +prev_bpsk = 1; +for i=1:N + + % BPSK -> DBPSK + + dbpsk(i) = bpsk(i) * (-prev_bpsk); + prev_bpsk = bpsk(i); + + % oversampling + + tx_bpsk((i-1)*M+1:i*M) = bpsk(i); + tx_dbpsk((i-1)*M+1:i*M) = dbpsk(i); +end + +figure(4); clf; +subplot(211); +plot(tx_bpsk, "linewidth", 4) +axis([0 10*M+1 -2 2]); +title('Tx BPSK'); +subplot(212); +plot(tx_dbpsk, "linewidth", 4) +axis([0 10*M+1 -2 2]); +title('Tx DBPSK'); +print("cohpsk_dbpsk1.png", "-dpng", "-S600,440", "-F:8") + +dbpsk *= -1; + +prev_rx = 1; +for i=1:N + + % rx DBPSK -> PSK + + bpsk(i) = dbpsk(i) * (prev_rx); + prev_rx = bpsk(i); + + % oversampling + + rx_bpsk((i-1)*M+1:i*M) = bpsk(i); + rx_dbpsk((i-1)*M+1:i*M) = dbpsk(i); +end + +figure(5); clf; +subplot(211); +plot(rx_dbpsk, "linewidth", 4) +axis([0 10*M+1 -2 2]); +title('Rx DBPSK with 180 deg phase shift'); +subplot(212); +plot(rx_bpsk, "linewidth", 4) +axis([0 10*M+1 -2 2]); +title('Rx BPSK'); +print("cohpsk_dbpsk2.png", "-dpng", "-S600,440", "-F:8") + diff --git a/codec2/branches/0.7/octave/crc16.m b/codec2/branches/0.7/octave/crc16.m new file mode 100644 index 00000000..aafc432f --- /dev/null +++ b/codec2/branches/0.7/octave/crc16.m @@ -0,0 +1,55 @@ +% crc16.m +% +%The CRC calculation is based on following generator polynomial: +%G(x) = x16 + x12 + x5 + 1 +% +%The register initial value of the implementation is: 0xFFFF +% +%used data = string -> 1 2 3 4 5 6 7 8 9 +% +% Online calculator to check the script: +%http://www.lammertbies.nl/comm/info/crc-calculation.html +% +% + +function crc = crc16(data) + + % crc look up table + + Crc_ui16LookupTable=[0,4129,8258,12387,16516,20645,24774,28903,33032,37161,41290,45419,49548,... + 53677,57806,61935,4657,528,12915,8786,21173,17044,29431,25302,37689,33560,45947,41818,54205,... + 50076,62463,58334,9314,13379,1056,5121,25830,29895,17572,21637,42346,46411,34088,38153,58862,... + 62927,50604,54669,13907,9842,5649,1584,30423,26358,22165,18100,46939,42874,38681,34616,63455,... + 59390,55197,51132,18628,22757,26758,30887,2112,6241,10242,14371,51660,55789,59790,63919,35144,... + 39273,43274,47403,23285,19156,31415,27286,6769,2640,14899,10770,56317,52188,64447,60318,39801,... + 35672,47931,43802,27814,31879,19684,23749,11298,15363,3168,7233,60846,64911,52716,56781,44330,... + 48395,36200,40265,32407,28342,24277,20212,15891,11826,7761,3696,65439,61374,57309,53244,48923,... + 44858,40793,36728,37256,33193,45514,41451,53516,49453,61774,57711,4224,161,12482,8419,20484,... + 16421,28742,24679,33721,37784,41979,46042,49981,54044,58239,62302,689,4752,8947,13010,16949,... + 21012,25207,29270,46570,42443,38312,34185,62830,58703,54572,50445,13538,9411,5280,1153,29798,... + 25671,21540,17413,42971,47098,34713,38840,59231,63358,50973,55100,9939,14066,1681,5808,26199,... + 30326,17941,22068,55628,51565,63758,59695,39368,35305,47498,43435,22596,18533,30726,26663,6336,... + 2273,14466,10403,52093,56156,60223,64286,35833,39896,43963,48026,19061,23124,27191,31254,2801,6864,... + 10931,14994,64814,60687,56684,52557,48554,44427,40424,36297,31782,27655,23652,19525,15522,11395,... + 7392,3265,61215,65342,53085,57212,44955,49082,36825,40952,28183,32310,20053,24180,11923,16050,3793,7920]; + + ui16RetCRC16 = hex2dec('FFFF'); + for I=1:length(data) + ui8LookupTableIndex = bitxor(data(I),uint8(bitshift(ui16RetCRC16,-8))); + ui16RetCRC16 = bitxor(Crc_ui16LookupTable(double(ui8LookupTableIndex)+1),mod(bitshift(ui16RetCRC16,8),65536)); + end + crc=dec2hex(ui16RetCRC16); + +endfunction + + + + + + + + + + + + diff --git a/codec2/branches/0.7/octave/cspec.m b/codec2/branches/0.7/octave/cspec.m new file mode 100644 index 00000000..e0ca15b6 --- /dev/null +++ b/codec2/branches/0.7/octave/cspec.m @@ -0,0 +1,54 @@ +% cspec.m +% David Rowe Aug 2012 +% Used to compare spectromgrams while experimenting with phase + +function cspec(s1,s2) + f1 = fopen(s1,"rb"); + s1 = fread(f1,Inf,"short"); + f2 = fopen(s2,"rb"); + s2 = fread(f2,Inf,"short"); + + Fs = 8000; + spec_win = 512; + + state = 's1'; + do + if strcmp(state,'s1') + spec(s1,Fs,spec_win); + %title(s1); + end + if strcmp(state,'s2') + spec(s2,Fs,spec_win); + %title(s2); + end + if strcmp(state,'diff') + spec(s1-s2,Fs,spec_win); + %title("difference"); + end + + printf("\rstate: %s space-toggle d-diff q-quit", state); + fflush(stdout); + k = kbhit(); + + if k == ' ' + if strcmp(state,"diff") + next_state = 's1'; + end + if strcmp(state,"s1") + next_state = 's2'; + end + if strcmp(state,'s2') + next_state = 's1'; + end + end + + if k == 'd' + next_state = 'diff'; + end + + state = next_state; + until (k == 'q') + + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/dacres.m b/codec2/branches/0.7/octave/dacres.m new file mode 100644 index 00000000..6d429362 --- /dev/null +++ b/codec2/branches/0.7/octave/dacres.m @@ -0,0 +1,165 @@ +% dacres.m +% David Rowe 18 Feb 2015 +% Brady O'Brien 5 Mar 2015 +% DAC upconversion simulation + +graphics_toolkit ("gnuplot"); + +cicn = 5; %delay for CIC filter +N = 5; %input interpolation rate +M = 25; %dac interpolation rate +csf = 1024; %scaling factor for CIC filter conversion +fd = 2E6; %DAC frequency +fs = 2E6/M/N; %Input sampling frequency +fi = 2E6/M; %freq of first interpolation +fb = 7E5; %Bandpass frequency +fc1 = fi/4; %Frequency of initial upconversion +ciccb=[-0.029626 0.252638 -2.304683 16.332166 -2.304683 0.252638 -0.029626]; %CIC Compensation FIR +pcicfb = fir1(41,.5); %Interpolation LPF Fir +s1fir = filter(ciccb,1,pcicfb); %Combine compensation and LPF +%s1fir = [-0.00000215, -0.00008715, 0.00073915, -0.00674415, 0.05618415, 0.01629015, -0.19074815, -0.04231615, 0.53620515, 0.09933915, -1.32978715, -0.38797815, 3.97887715, 6.70888315, 3.97887715, -0.38797815, -1.32978715, 0.09933915, 0.53620515, -0.04231615, -0.19074815, ]; + +t = (1:fs/2); +scpin = e.^(i*(t*pi*2*(3000/8000))); % initial complex input +%scpin = zeros(1,length(t)); +scpin(1) = 1+i; + +intstage1 = zeros(1,2*length(scpin)); %First stage of interpolation, 2x +intstage1(1:2:2*length(scpin))=scpin; + +scireal = int32(filter(s1fir,1,real(intstage1))*csf); %separate input into real and imiginary and apply pre-distortion +sciimag = int32(filter(s1fir,1,imag(intstage1))*csf); % also convert to integer. CIC integrator needs integer to work properly + +%Apply 3 stage comb to real +fdin = scireal; +combout1=0; +combout2=0; +combout3=0; +combout4=0; +ccbuf1=zeros(1,cicn/N); +ccbuf2=zeros(1,cicn/N); +ccbuf3=zeros(1,cicn/N); +ccbuf4=zeros(1,cicn/N); + +for ii=1:length(fdin) + combout1 = fdin(ii) - ccbuf1(end); + combout2 = combout1 - ccbuf2(end); + combout3 = combout2 - ccbuf3(end); + combout4 = combout3 - ccbuf4(end); + ccbuf1(2:end)=ccbuf1(1:end-1); + ccbuf2(2:end)=ccbuf2(1:end-1); + ccbuf3(2:end)=ccbuf3(1:end-1); + ccbuf4(2:end)=ccbuf4(1:end-1); + ccbuf1(1)=fdin(ii); + ccbuf2(1)=combout1; + ccbuf3(1)=combout2; + ccbuf4(1)=combout3; + fdcout(ii)=combout4; +end + +intout1=0; +intout2=0; +intout3=0; +intout4=0; +fdnext = zeros(1,length(fdcout)*N); +fdnext(1:N:length(fdcout)*N) = fdcout; %Interpolate + +for ii=1:length(fdnext) + intout1 = fdnext(ii) + intout1; + intout2 = intout1 + intout2; + intout3 = intout2 + intout3; + intout4 = intout3 + intout4; + fdnext(ii)=intout4; +end +scoreal=single(fdnext/(2**20)); + +fdin=sciimag; + +%Apply 3 stage comb to imag +combout1=0; +combout2=0; +combout3=0; +combout4=0; +ccbuf1=zeros(1,cicn/N); +ccbuf2=zeros(1,cicn/N); +ccbuf3=zeros(1,cicn/N); +ccbuf4=zeros(1,cicn/N); + +for ii=1:length(fdin) + combout1 = fdin(ii) - ccbuf1(end); + combout2 = combout1 - ccbuf2(end); + combout3 = combout2 - ccbuf3(end); + combout4 = combout3 - ccbuf4(end); + ccbuf1(2:end)=ccbuf1(1:end-1); + ccbuf2(2:end)=ccbuf2(1:end-1); + ccbuf3(2:end)=ccbuf3(1:end-1); + ccbuf4(2:end)=ccbuf4(1:end-1); + ccbuf1(1)=fdin(ii); + ccbuf2(1)=combout1; + ccbuf3(1)=combout2; + ccbuf4(1)=combout3; + fdcout(ii)=combout4; +end + +intout1=0; +intout2=0; +intout3=0; +intout4=0; +fdnext = zeros(1,length(fdcout)*N); +fdnext(1:N:length(fdcout)*N) = fdcout; %Interpolate + +for ii=1:length(fdnext) + intout1 = fdnext(ii) + intout1; + intout2 = intout1 + intout2; + intout3 = intout2 + intout3; + intout4 = intout3 + intout4; + fdnext(ii)=intout4; +end +scoimag=single(fdnext/(2**20)); + +%Convert complex to real and shift up to Fs/4 +ssout = scoreal.*cos(pi*.5*(1:length(scoreal))) + scoimag.*sin(pi*.5*(1:length(scoimag))); + + +t = (0:(fi-1)); + +beta1 = 0.999; +b1x = -2*sqrt(beta1)*cos(2*pi*(fb/fd)) +beta2 = beta1 - (1-beta1)*M; + +sducin = ssout; +%sducin = cos(pi*.5*t); + +sduceq = filter([1 0 beta2],1,sducin); %pre interpolation notch filter to equalize bandpass after interpolation +sducinterp = zeros(1,length(sduceq)*M); %interpolate by zero-stuffing +sducinterp(1:M:length(sduceq)*M) = sduceq; +sdac = filter(1,[1 b1x beta1],sducinterp); %select wanted signal + +sdac = sdac + median(sdac); %Center above zero +sdac = sdac / max(sdac); %normalize +sdac = int32(sdac*2000); %integerize +sdac = sdac + sdac .^ 5; + +figure(1) +subplot(211) +plot(20*log10(abs(fft(sducin)/fi))) +grid +axis([0 fi/2 -20 50]) +title('Output from modem'); +subplot(212) +plot(20*log10(abs(fft(sduceq/fi)))) +grid +axis([0 fi/2 -20 70]) +title('After Pre-eq'); + +figure(2) +subplot(211) +plot(20*log10(abs(fft(sducinterp)/fd))) +grid +axis([0 (fd/2) -20 80]) +title('After interpolation'); +subplot(212) +plot(20*log10(abs(fft(sdac)/fd))) +grid +title('After bandpass'); +%axis([0 (fd/2) -20 80]) diff --git a/codec2/branches/0.7/octave/df_mixer.m b/codec2/branches/0.7/octave/df_mixer.m new file mode 100644 index 00000000..9f744ed2 --- /dev/null +++ b/codec2/branches/0.7/octave/df_mixer.m @@ -0,0 +1,272 @@ +% df_mixer.m +% +% David Rowe October 2015 +% +% Experimental direction finding using a mixer to FDM signals from two +% antennas. This simulation tests estimation of phase and freq of +% mixer LO. +% +% [X] built in hackrf_dc +% [X] test mode +% [X] compass needle +% [X] real time operation (or close to it) + +fm; + +% Generate a FM modulated signal for testing ---------------------------------- + +function tx = fm_mod(Fs, fmod) + fm_states.Fs = Fs; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.fc = 48E3; + fm_states.pre_emp = 0; + fm_states.de_emp = 0; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + + nsam = fm_states.Fs/2; + t = 0:(nsam-1); + wmod = 2*pi*fmod/fm_states.Fs; + mod = sin(wmod*t); + tx = analog_fm_mod(fm_states, mod); +endfunction + + +% Check Filters ------------------------------------------------------------- + +% Run some test signals through all three filters. Real signals used +% for convenience, also works with complex. If another set of filter +% is used you need to prove net reponse is a delay. Fig 2 +% subplot(211) must be a straight line. + +function check_filters(bcentre, Fs, f, bw, w, wlo, t) + x = cos(w*t) + cos((w-wlo)*t) + cos((w-wlo)*t); + ycenter = filter(bcentre,1,x); + ylow = exp(-j*wlo*t) .* filter(bcentre, 1, x .* exp(j*wlo*t)); + yhigh = exp(j*wlo*t) .* filter(bcentre, 1, x .* exp(-j*wlo*t)); + y = ycenter + ylow + yhigh; + + figure(1) + clf + h=freqz(bcentre,1,Fs/2); + plot(20*log10(abs(h))) + hold on; + plot([f-bw/2 f-bw/2 f+bw/2 f+bw/2],[-60 -3 -3 -60],'r'); + hold off; + axis([f-bw f+bw -60 0]) + title('Centre BPF'); + grid; + + figure(2) + clf; + Ns = 200; + Np = 200; + + % y should be a delayed version of x + + subplot(211) + plot(x(Ns:Ns+Np-1)) + hold on; + plot(y(Ns:Ns+Np-1),'g') + hold off; + title('Filter Check'); + + % should see a straight line on this plot + + subplot(212) + plot(x(Ns:Ns+Np-1), y(Ns:Ns+Np-1)) +end + + +% Constants ------------------------------------------------------------------- + +randn('state',1); +more off; +format short + +f = 48E3; % signal frequency +flo = 32.768E3; % LO frequency +m = 10^(-0/20); % modulation index of our mixer, how far each + % sideband is down wrt carrier (0.1 == 20dB) + % note: not FM modulation index +bw = 16E3; % signal bandwidth + +phi = 0.5; % phase difference between antennas - + % ->> what we are trying to estimate + +theta = 0; % phase term constant to ant1 and ant2 +alpha = 0; % LO phase + +Fs = 200E3; % sample rate +Fshrf = 10E6; % HackRF sample rate +CNodB = 100; % C/No of carrier, which dominates power + % Around C/No = 50dB is min for FM (12dB-ish SINAD) +fmod = 0; % Audio modulation on FM signal (0 for carrier) +N = Fs/2; % processing block size + +% BW is Fs Hz. No=(total noise power Nt)/Fs. N=noise power=variance of noise source +% C = carrier power = 1 +% CNo = C/No = 1/(Nt/Fs), therefore var = Nt = Fs/CNo + +CNo = 10^(CNodB/10); +var = Fs/CNo; + +w = 2*pi*f/Fs; +wlo = 2*pi*flo/Fs; +wbw = 2*pi*bw/Fs; + +% FIR filter BPF for centre signal. Use a 15kHz cut off to catch +% energy from FM signals. Important: we need identical phase response +% for each BPF. I couldn't work out how to design these filter using +% the built-in Octave functions. So I use a bunch of freq shifts at +% run time instead, so we use the centre BPF for all three filters. + +bcentre = fir2(200, [0, f-bw/2, f, f+bw/2, Fs/2]/(Fs/2), [0 0 1 0 0]); + +%check_filters(bcentre, Fs, f, bw, w, wlo, t); xx + +% Main ------------------------------------------------------------------------- + +mode = "sample"; +finished = 0; +while !finished + + if strcmp(mode, "simulate") + % Simulate rx signal --------------------------------------------------------- + + t=0:N-1; + + % tx signal + + tx = fm_mod(Fs, fmod); + + % simulate rx signals at antenna 1 and 2 by adding noise. Note signal + % at antenna 2 is phase shifted phi due to path difference. Both signals + % experience a time of flight path different theta. + + n = sqrt(var/2)*randn(1,N) + j*sqrt(var/2)*randn(1,N); + ant1 = tx*exp(j*(theta+phi)) + n; + ant2 = tx*exp(j*(theta)) + n; + + % ant2 passed through mixer with local osc frequency wlo and phase alpha + + ant2_mix = 2.0*m*(ant2 .* cos(t*wlo + alpha)); + + % The SDR receives the sum of the two signals + + rx = ant1 + ant2_mix; + end + + if strcmp(mode,"file") || strcmp(mode,"sample") + % Off air signal from HackRF stored in file ---------------------------------------------- + + if strcmp(mode,"sample") + [status output] = system("hackrf_transfer -r df1.iq -f 439000000 -n 10000000 -l 20 -g 40"); + end + s1 = load_hackrf("df1.iq"); + rx = downsample(rot90(s1), Fshrf/Fs)/127; + t = 1:length(rx); + end + + Rx = (1/N)*fft(rx,N); + + % BPF each signal + + sam1 = filter(bcentre,1,rx); + sam2 = exp( j*wlo*t) .* filter(bcentre, 1, rx .* exp(-j*wlo*t)); + sam3 = exp(-j*wlo*t) .* filter(bcentre, 1, rx .* exp( j*wlo*t)); + + % Do the math on phases using rect math + + two_phi_est_rect = conj(sam2.*sam3) .* (sam1.^2); + phi_est = angle(two_phi_est_rect)/2; + + phi_est_av = angle(mean(two_phi_est_rect))/2; + + printf("phi_est : %3.2f rads %3.1f degrees\n", phi_est_av, phi_est_av*180/pi); + + % some plots .... + + figs = 0x1 + 0x2 + 0x20; + + if bitand(figs, 0x1) + figure(1); + clf; + plot((1:N)*Fs/N, 20*log10(abs(Rx)),'markersize', 10, 'linewidth', 2); + axis([1 Fs -80 0]) + title('Rx signal at SDR input'); + end + + if bitand(figs, 0x2) + figure(2) + clf + Sam1 = (1/N)*fft(sam1,N); + Sam2 = (1/N)*fft(sam2,N); + Sam3 = (1/N)*fft(sam3,N); + subplot(311) + plot((1:N)*Fs/N, 20*log10(abs(Sam1)),'markersize', 10, 'linewidth', 2); + axis([f-bw/2 f+bw/2 -60 0]) + title('Band Pass filtered signals'); + subplot(312) + plot((1:N)*Fs/N, 20*log10(abs(Sam2)),'markersize', 10, 'linewidth', 2); + axis([f+flo-bw/2 f+flo+bw/2 -60 0]) + subplot(313) + plot((1:N)*Fs/N, 20*log10(abs(Sam3)),'markersize', 10, 'linewidth', 2); + axis([f-flo-bw/2 f-flo+bw/2 -60 0]) + end + + if bitand(figs, 0x4) + figure(3) + Np = 1000; + subplot(311) + plot(real(sam1(1:Np))) + title('Band Pass filtered signals'); + subplot(312) + plot(real(sam2(1:Np))) + subplot(313) + plot(real(sam3(1:Np))) + end + + if bitand(figs, 0x8) + figure(4) + clf; + hist2d([real(two_phi_est_rect)' imag(two_phi_est_rect)'],50) + xmax = 2*mean(abs(two_phi_est_rect)); + axis([-xmax xmax -xmax xmax]) + title('Scatter Plot'); + end + + if bitand(figs, 0x10) + figure(5) + clf; + subplot(211) + plot(real(two_phi_est_rect(1:Np))) + subplot(212) + plot(imag(two_phi_est_rect(1:Np))) + title('two phi est rect') + end + + if bitand(figs, 0x20) + figure(6) + clf + [r theta] = hist([angle(two_phi_est_rect)/2 -pi/2 pi/2],100); + polar([theta pi+theta],[r r]) + end + + if bitand(figs, 0x40) + figure(7) + clf + plot(phi_est) + axis([0 length(phi_est(1:Np)) -pi/2 pi/2]); + title('phi est') + end + + % when sampling hit any key to finish, finish after one pass in other modes + + finished = 1; + if strcmp(mode, "sample") + finished = length(kbhit(1)); + end +end diff --git a/codec2/branches/0.7/octave/diff_codec.m b/codec2/branches/0.7/octave/diff_codec.m new file mode 100644 index 00000000..2ad204ff --- /dev/null +++ b/codec2/branches/0.7/octave/diff_codec.m @@ -0,0 +1,96 @@ +% diff_codec.m +% +% Plots differences between two states in two runs of the codec, +% e.g. x86 and embedded. +% +% Copyright David Rowe 2013 +% +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +function diff_codec(samname1, samname2, model1_prefix, model2_prefix) + + fs1=fopen(samname1,"rb"); + s1=fread(fs1,Inf,"short"); + fs2=fopen(samname2,"rb"); + s2=fread(fs2,Inf,"short"); + + st = 1; + en = length(s1); + + figure(1); + clf; + subplot(211); + l1 = strcat("r;",samname1,";"); + plot(s1(st:en), l1); + axis([1 en-st min(s1(st:en)) max(s1(st:en))]); + subplot(212); + l2 = strcat("r;",samname2,";"); + plot(s2(st:en),l2); + axis([1 en-st min(s1(st:en)) max(s1(st:en))]); + + figure(2) + plot(s1(st:en)-s2(st:en)); + max(s1(st:en)-s2(st:en)); + + model_name1 = strcat(model1_prefix,"_model.txt"); + model1 = load(model_name1); + model_name1q = strcat(model1_prefix,"_qmodel.txt"); + model1q = load(model_name1q); + + model_name2 = strcat(model2_prefix,"_model.txt"); + model2 = load(model_name2); + model_name2q = strcat(model2_prefix,"_qmodel.txt"); + model2q = load(model_name2q); + + Wo1 = model1(:,1); + L1 = model1(:,2); + Am1 = model1(:,3:82); + Wo1q = model1q(:,1); + L1q = model1q(:,2); + Am1q = model1q(:,3:82); + + Wo2 = model2(:,1); + L2 = model2(:,2); + Am2 = model2(:,3:82); + Wo2q = model2q(:,1); + L2q = model2q(:,2); + Am2q = model2q(:,3:82); + + figure(3) + subplot(211) + plot(Wo1) + title('Wo1'); + subplot(212) + plot(Wo1-Wo2) + figure(4) + subplot(211) + plot(Wo1q) + title('Wo1q'); + subplot(212) + plot(Wo1q-Wo2q) + + figure(5) + subplot(211) + plot(L1) + title('L1'); + subplot(212) + plot(L1-L2) + figure(6) + subplot(211) + plot(L1q) + title('L1q'); + subplot(212) + plot(L1q-L2q) + + figure(7) + l=length(L1q); + sm=zeros(1,l); + for f=1:l + %printf("f %d L1q %d L2q %d\n",f,L1q(f),L2q(f)); + sm(f) = sum(10*log10(Am1q(f,1:L1q(f))) - 10*log10(Am2q(f,1:L2q(f)))); + end + plot(sm) + title('Am1q - Am2q'); + +endfunction diff --git a/codec2/branches/0.7/octave/doppler_spread.m b/codec2/branches/0.7/octave/doppler_spread.m new file mode 100644 index 00000000..4bc6c62a --- /dev/null +++ b/codec2/branches/0.7/octave/doppler_spread.m @@ -0,0 +1,37 @@ +% doppler_spread.m +% David Rowe Jan 2016 +% +% Returns gausssian filtered doppler spreading function samples for HF channel +% modelling. Used PathSim technical guide as a reference - thanks Moe! + +function [spread_FsHz states] = doppler_spread(dopplerSpreadHz, FsHz, Nsam) + + % start with low Fs so we can work with a reasonable filter length + + sigma = dopplerSpreadHz/2; + lowFs = 10*dopplerSpreadHz; + Ntaps = 100; + Nsam_low = Nsam*lowFs/FsHz + Ntaps; % fill filter memory + + % generate gaussian freq response and design filter + + x = 0:0.1:lowFs/2; + y = (1/(sigma*sqrt(2*pi)))*exp(-(x.^2)/(2*sigma*sigma)); + b = fir2(Ntaps-1, x/(lowFs/2), y); + + % generate the spreading samples + + spread_lowFs = filter(b,1,randn(1,Nsam_low) + j*randn(1,Nsam_low)); + + % resample to FsHz, scaling for desired spreadFreqHz + + spread_FsHz = resample(spread_lowFs(Ntaps+1:Nsam_low), FsHz, lowFs); + + % return some states for optional unit testing + states.x = x; + states.y = y; + states.b = b; + +endfunction + + diff --git a/codec2/branches/0.7/octave/doppler_spread_ut.m b/codec2/branches/0.7/octave/doppler_spread_ut.m new file mode 100644 index 00000000..f7d96b01 --- /dev/null +++ b/codec2/branches/0.7/octave/doppler_spread_ut.m @@ -0,0 +1,51 @@ +% doppler_spread_ut.m +% David Rowe Jan 2016 +% +% Unit test script for doppler_spread + +f = 1; +Fs = 8000; +N = Fs*10; + +[spread states] = doppler_spread(f, Fs, N); + +% use spreading samples to modulate 1000Hz sine wave +% You can listen to this with: sine1k_1Hz.raw + +% $ play -t raw -r 8000 -s -2 +s = cos(2*pi*(1:N)*1000/Fs); +s = s .* spread; +s = real(s)*5000; +fs = fopen("sine1k_1Hz.raw","wb"); fwrite(fs,s,"short"); fclose(fs); + +% Some plots + +x = states.x; y = states.y; b = states.b; + +H = freqz(b,1,x); + +figure(1) +clf +subplot(211) +plot(x,y,';target;') +title('Gaussian Filter Freq Resp Lin'); +legend('boxoff'); +subplot(212) +plot(x,20*log10(y),';target;') +hold on; +plot(x,20*log10(y),'g+;actual;') +hold off; +axis([0 f*10/2 -60 0]) +title('Gaussian Filter Freq Resp dB'); +xlabel('Freq (Hz)'); +legend('boxoff'); + +figure(2); +subplot(211) +plot(abs(spread)) +title('Spreading Function Magnitude'); +subplot(212) +plot(s) +title('1000Hz Sine Wave'); +xlabel('Time (samples)') + diff --git a/codec2/branches/0.7/octave/estsnr.m b/codec2/branches/0.7/octave/estsnr.m new file mode 100644 index 00000000..5a00bd80 --- /dev/null +++ b/codec2/branches/0.7/octave/estsnr.m @@ -0,0 +1,65 @@ +% estsnr.m +% David Rowe May 2017 +% +% estimate SNR of a sinewave in noise + +function snr_dB = estsnr(x, Fs=8000, Nbw = 3000) + + [nr nc] = size(x); + if nr == 1 + x = x'; + end + + % find peak in +ve side of spectrum, ignoring DC + + L = length(x); + X = abs(fft(x)); + st = floor(0.05*L); en = floor(0.45*L); + [A mx_ind]= max(X(st:en)); + mx_ind += st; + + % signal energy might be spread by doppler, so sum energy + % in frequencies +/- 1% + + s_st = floor(mx_ind*0.99); s_en = floor(mx_ind*1.01); + S = sum(X(s_st:s_en).^2); + + % real signal, so -ve power is the same + + S = 2*S; + SdB = 10*log10(S); + + printf("Signal Power S: %3.2f dB\n", SdB); + + % locate a band of noise next to it and find power in band + + st = floor(mx_ind+0.05*(L/2)); + en = st + floor(0.1*(L/2)); + + N = sum(X(st:en).^2); + + % scale this to obtain total noise power across total bandwidth + + N *= L/(en-st); + NdB = 10*log10(N); + printf("Noise Power N: %3.2f dB\n", NdB); + + % scale noise to designed noise bandwidth /2 fudge factor as its a + % real signal, wish I had a better way to explain that! + + NodB = NdB - 10*log10(Fs/2); + NscaleddB = NodB + 10*log10(Nbw); + snr_dB = SdB - NscaleddB; + + figure(1); clf; + plot(20*log10(X(1:L/2)),'b'); + hold on; + plot([s_st s_en], [NdB NdB]- 10*log10(L), 'r'); + plot([st en], [NdB NdB]- 10*log10(L), 'r'); + hold off; + top = 10*ceil(SdB/10); + bot = NodB - 20; + axis([1 L/2 bot top]); + grid + grid("minor") +endfunction diff --git a/codec2/branches/0.7/octave/fdmdv.m b/codec2/branches/0.7/octave/fdmdv.m new file mode 100644 index 00000000..a7965b33 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv.m @@ -0,0 +1,1164 @@ +% fdmdv.m +% +% Functions that implement a Frequency Divison Multiplexed Modem for +% Digital Voice (FDMDV) over HF channels. +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% TODO: +% [X] refactor with states +% [X] remove commented out globals +% [X] tfdmdv works +% [ ] fdmdv_ut works + +% reqd to make sure we get same random bits at mod and demod + +rand('state',1); +randn('state',1); + +% Functions ---------------------------------------------------- + + +function f = fdmdv_init + Fs = f.Fs = 8000; % sample rate in Hz + T = f.T = 1/Fs; % sample period in seconds + Rs = f.Rs = 50; % symbol rate in Hz + Nc = f.Nc = 14; + Nb = f.Nb = 2; % Bits/symbol for PSK modulation + Rb = f.Rb = Nc*Rs*Nb; % bit rate + M = f.M = Fs/Rs; % oversampling factor + Nsym = f.Nsym = 6; % number of symbols to filter over + + Fsep = f.Fsep = 75; % Separation between carriers (Hz) + Fcenter = f.Fcentre = 1500; % Centre frequency, Nc/2 carriers below this, + % Nc/2 carriers above (Hz) + Nt = f.Nt = 5; % number of symbols we estimate timing over + P = f.P = 4; % oversample factor used for rx symbol filtering + Nfilter = f.Nfilter = Nsym*M; + + Nfiltertiming = f.Nfiltertiming = M+Nfilter+M; + + Nsync_mem = f.Nsync_mem = 6; + f.sync_uw = [1 -1 1 -1 1 -1]; + + alpha = 0.5; + f.gt_alpha5_root = gen_rn_coeffs(alpha, T, Rs, Nsym, M); + + f.pilot_bit = 0; % current value of pilot bit + + f.tx_filter_memory = zeros(Nc+1, Nfilter); + f.rx_filter_memory = zeros(Nc+1, Nfilter); + f.rx_fdm_mem = zeros(1,Nfilter+M); + + f.snr_coeff = 0.9; % SNR est averaging filter coeff + + % phasors used for up and down converters + + f.freq = zeros(Nc+1,1); + f.freq_pol = zeros(Nc+1,1); + + for c=1:Nc/2 + carrier_freq = (-Nc/2 - 1 + c)*Fsep; + f.freq_pol(c) = 2*pi*carrier_freq/Fs; + f.freq(c) = exp(j*f.freq_pol(c)); + end + + for c=floor(Nc/2)+1:Nc + carrier_freq = (-Nc/2 + c)*Fsep; + f.freq_pol(c) = 2*pi*carrier_freq/Fs; + f.freq(c) = exp(j*f.freq_pol(c)); + end + + f.freq_pol(Nc+1) = 2*pi*0/Fs; + f.freq(Nc+1) = exp(j*f.freq_pol(Nc+1)); + + f.fbb_rect = exp(j*2*pi*f.Fcentre/Fs); + f.fbb_phase_tx = 1; + f.fbb_phase_rx = 1; + + % Spread initial FDM carrier phase out as far as possible. This + % helped PAPR for a few dB. We don't need to adjust rx phase as DQPSK + % takes care of that. + + f.phase_tx = ones(Nc+1,1); + f.phase_tx = exp(j*2*pi*(0:Nc)/(Nc+1)); + f.phase_rx = ones(Nc+1,1); + + % decimation filter + + f.Nrxdec = 31; + % fir1() output appears to have changed from when coeffs used in C port were used + %f.rxdec_coeff = fir1(f.Nrxdec-1, 0.25); + f.rxdec_coeff = [-0.00125472 -0.00204605 -0.0019897 0.000163906 0.00490937 0.00986375 ... + 0.0096718 -0.000480351 -0.019311 -0.0361822 -0.0341251 0.000827866 ... + 0.0690577 0.152812 0.222115 0.249004 0.222115 0.152812 ... + 0.0690577 0.000827866 -0.0341251 -0.0361822 -0.019311 -0.000480351 ... + 0.0096718 0.00986375 0.00490937 0.000163906 -0.0019897 -0.00204605 ... + -0.00125472]; + + f.rxdec_lpf_mem = zeros(1,f.Nrxdec-1+M); + f.Q=M/4; + + % freq offset estimation + + f.Mpilotfft = 256; + f.Npilotcoeff = 30; + + % here's how to make this filter from scratch, however it appeared to change over different + % octave versions so have hard coded to version used for C port + %f.pilot_coeff = fir1(f.Npilotcoeff-1, 200/(Fs/2))'; % 200Hz LPF + f.pilot_coeff = [0.00223001 0.00301037 0.00471258 0.0075934 0.0118145 0.0174153 ... + 0.0242969 0.0322204 0.0408199 0.0496286 0.0581172 0.0657392 ... + 0.0719806 0.0764066 0.0787022 0.0787022 0.0764066 0.0719806 ... + 0.0657392 0.0581172 0.0496286 0.0408199 0.0322204 0.0242969 ... + 0.0174153 0.0118145 0.0075934 0.00471258 0.00301037 0.00223001]; + + f.Npilotbaseband = f.Npilotcoeff + M + M/P; % number of pilot baseband samples + f.Npilotlpf = 4*M; % reqd for pilot LPF + % number of symbols we DFT pilot over + % pilot est window + + % pilot LUT, used for copy of pilot at rx + + f.pilot_lut = generate_pilot_lut(f); + f.pilot_lut_index = 1; + f.prev_pilot_lut_index = 3*M+1; + + % Freq offset estimator states + + f.pilot_baseband1 = zeros(1, f.Npilotbaseband); % pilot baseband samples + f.pilot_baseband2 = zeros(1, f.Npilotbaseband); % pilot baseband samples + f.pilot_lpf1 = zeros(1, f.Npilotlpf); % LPF pilot samples + f.pilot_lpf2 = zeros(1, f.Npilotlpf); % LPF pilot samples + + % Timing estimator states + + f.rx_filter_mem_timing = zeros(Nc+1, Nt*P); + f.rx_baseband_mem_timing = zeros(Nc+1, f.Nfiltertiming); + + % Test bit stream state variables + + f = init_test_bits(f); +endfunction + + +% generate Nc+1 PSK symbols from vector of (1,Nc*Nb) input bits. The +% Nc+1 symbol is the +1 -1 +1 .... BPSK sync carrier + +function [tx_symbols f] = bits_to_psk(f, prev_tx_symbols, tx_bits) + Nc = f.Nc; Nb = f.Nb; + m4_gray_to_binary = [ + bin2dec("00") + bin2dec("01") + bin2dec("11") + bin2dec("10") + ]; + m8_gray_to_binary = [ + bin2dec("000") + bin2dec("001") + bin2dec("011") + bin2dec("010") + bin2dec("111") + bin2dec("110") + bin2dec("100") + bin2dec("101") + ]; + + assert(length(tx_bits) == Nc*Nb, "Incorrect number of bits"); + + m = 2 .^ Nb; + assert((m == 4) || (m == 8)); + + for c=1:Nc + + % extract bits for this symbol + + bits_binary = tx_bits((c-1)*Nb+1:c*Nb); + bits_decimal = sum(bits_binary .* 2.^(Nb-1:-1:0)); + + % determine phase shift using gray code mapping + + if m == 4 + phase_shift = (2*pi/m)*m4_gray_to_binary(bits_decimal+1); + else + phase_shift = (2*pi/m)*m8_gray_to_binary(bits_decimal+1); + end + + % apply phase shift from previous symbol + + tx_symbols(c) = exp(j*phase_shift) * prev_tx_symbols(c); + end + + % +1 -1 +1 -1 BPSK sync carrier, once filtered becomes two spectral + % lines at +/- Rs/2 + + if f.pilot_bit + tx_symbols(Nc+1) = -prev_tx_symbols(Nc+1); + else + tx_symbols(Nc+1) = prev_tx_symbols(Nc+1); + end + if f.pilot_bit + f.pilot_bit = 0; + else + f.pilot_bit = 1; + end + +endfunction + + +% Given Nc symbols construct M samples (1 symbol) of Nc filtered +% symbols streams + +function [tx_baseband fdmdv] = tx_filter(fdmdv, tx_symbols) + Nc = fdmdv.Nc; + M = fdmdv.M; + tx_filter_memory = fdmdv.tx_filter_memory; + Nfilter = fdmdv.Nfilter; + gt_alpha5_root = fdmdv.gt_alpha5_root; + + tx_baseband = zeros(Nc+1,M); + + % tx filter each symbol, generate M filtered output samples for each symbol. + % Efficient polyphase filter techniques used as tx_filter_memory is sparse + + tx_filter_memory(:,Nfilter) = sqrt(2)/2*tx_symbols; + + for i=1:M + tx_baseband(:,i) = M*tx_filter_memory(:,M:M:Nfilter) * gt_alpha5_root(M-i+1:M:Nfilter)'; + end + tx_filter_memory(:,1:Nfilter-M) = tx_filter_memory(:,M+1:Nfilter); + tx_filter_memory(:,Nfilter-M+1:Nfilter) = zeros(Nc+1,M); + + fdmdv.tx_filter_memory = tx_filter_memory; +endfunction + + +% Construct FDM signal by frequency shifting each filtered symbol +% stream. Returns complex signal so we can apply frequency offsets +% easily. + +function [tx_fdm fdmdv] = fdm_upconvert(fdmdv, tx_filt) + Fs = fdmdv.Fs; + M = fdmdv.M; + Nc = fdmdv.Nc; + Fsep = fdmdv.Fsep; + phase_tx = fdmdv.phase_tx; + freq = fdmdv.freq; + fbb_rect = fdmdv.fbb_rect; + fbb_phase_tx = fdmdv.fbb_phase_tx; + + tx_fdm = zeros(1,M); + + % Nc+1 tones + + for c=1:Nc+1 + for i=1:M + phase_tx(c) = phase_tx(c) * freq(c); + tx_fdm(i) = tx_fdm(i) + tx_filt(c,i)*phase_tx(c); + end + end + + % shift up to carrier freq + + for i=1:M + fbb_phase_tx *= fbb_rect; + tx_fdm(i) = tx_fdm(i) * fbb_phase_tx; + end + + % Scale such that total Carrier power C of real(tx_fdm) = Nc. This + % excludes the power of the pilot tone. + % We return the complex (single sided) signal to make frequency + % shifting for the purpose of testing easier + + tx_fdm = 2*tx_fdm; + + % normalise digital oscillators as the magnitude can drift over time + + for c=1:Nc+1 + mag = abs(phase_tx(c)); + phase_tx(c) /= mag; + end + mag = abs(fbb_phase_tx); + fbb_phase_tx /= mag; + + fdmdv.fbb_phase_tx = fbb_phase_tx; + fdmdv.phase_tx = phase_tx; +endfunction + + +% Frequency shift each modem carrier down to Nc+1 baseband signals + +function [rx_baseband fdmdv] = fdm_downconvert(fdmdv, rx_fdm, nin) + Fs = fdmdv.Fs; + M = fdmdv.M; + Nc = fdmdv.Nc; + phase_rx = fdmdv.phase_rx; + freq = fdmdv.freq; + + rx_baseband = zeros(Nc+1,nin); + + for c=1:Nc+1 + for i=1:nin + phase_rx(c) = phase_rx(c) * freq(c); + rx_baseband(c,i) = rx_fdm(i)*phase_rx(c)'; + end + end + + for c=1:Nc+1 + mag = abs(phase_rx(c)); + phase_rx(c) /= mag; + end + + fdmdv.phase_rx = phase_rx; +endfunction + + +% Receive filter each baseband signal at oversample rate P + +function [rx_filt fdmdv] = rx_filter(fdmdv, rx_baseband, nin) + Nc = fdmdv.Nc; + M = fdmdv.M; + P = fdmdv.P; + rx_filter_memory = fdmdv.rx_filter_memory; + Nfilter = fdmdv.Nfilter; + gt_alpha5_root = fdmdv.gt_alpha5_root; + + rx_filt = zeros(Nc+1,nin*P/M); + + % rx filter each symbol, generate P filtered output samples for each symbol. + % Note we keep memory at rate M, it's just the filter output at rate P + + N=M/P; + j=1; + for i=1:N:nin + rx_filter_memory(:,Nfilter-N+1:Nfilter) = rx_baseband(:,i:i-1+N); + rx_filt(:,j) = rx_filter_memory * gt_alpha5_root'; + rx_filter_memory(:,1:Nfilter-N) = rx_filter_memory(:,1+N:Nfilter); + j+=1; + end + + fdmdv.rx_filter_memory = rx_filter_memory; +endfunction + + +% LP filter +/- 1000 Hz, allows us to perfrom rx filtering at a lower rate saving CPU + +function [rx_fdm_filter fdmdv] = rxdec_filter(fdmdv, rx_fdm, nin) + M = fdmdv.M; + Nrxdec = fdmdv.Nrxdec; + rxdec_coeff = fdmdv.rxdec_coeff; + rxdec_lpf_mem = fdmdv.rxdec_lpf_mem; + + rxdec_lpf_mem(1:Nrxdec-1+M-nin) = rxdec_lpf_mem(nin+1:Nrxdec-1+M); + rxdec_lpf_mem(Nrxdec-1+M-nin+1:Nrxdec-1+M) = rx_fdm(1:nin); + + rx_fdm_filter = zeros(1,nin); + for i=1:nin + rx_fdm_filter(i) = rxdec_lpf_mem(i:Nrxdec-1+i) * rxdec_coeff'; + end + + fdmdv.rxdec_lpf_mem = rxdec_lpf_mem; +end + + +% Combined down convert and rx filter, more memory efficient but less intuitive design +% TODO: Decimate mem update and downconversion, this will save some more CPU and memory +% note phase would have to advance 4 times as fast + +function [rx_filt fdmdv] = down_convert_and_rx_filter(fdmdv, rx_fdm, nin, dec_rate) + Nc = fdmdv.Nc; + M = fdmdv.M; + P = fdmdv.P; + rx_fdm_mem = fdmdv.rx_fdm_mem; + phase_rx = fdmdv.phase_rx; + freq = fdmdv.freq; + freq_pol = fdmdv.freq_pol; + Nfilter = fdmdv.Nfilter; + gt_alpha5_root = fdmdv.gt_alpha5_root; + Q = fdmdv.Q; + + % update memory of rx_fdm + + rx_fdm_mem(1:Nfilter+M-nin) = rx_fdm_mem(nin+1:Nfilter+M); + rx_fdm_mem(Nfilter+M-nin+1:Nfilter+M) = rx_fdm(1:nin); + + for c=1:Nc+1 + + % now downconvert using current freq offset to get Nfilter+nin + % baseband samples. + % + % Nfilter nin + % |--------------------------|---------| + % | + % phase_rx(c) + % + % This means winding phase(c) back from this point + % to ensure phase continuity + + wind_back_phase = -freq_pol(c)*Nfilter; + phase_rx(c) = phase_rx(c)*exp(j*wind_back_phase); + + % down convert all samples in buffer + + rx_baseband = zeros(1,Nfilter+M); + st = Nfilter+M; % end of buffer + st -= nin-1; % first new sample + st -= Nfilter; % first sample used in filtering + + f_rect = freq(c) .^ dec_rate; + + for i=st:dec_rate:Nfilter+M + phase_rx(c) = phase_rx(c) * f_rect; + rx_baseband(i) = rx_fdm_mem(i)*phase_rx(c)'; + end + + % now we can filter this carrier's P symbols. Due to filtering of rx_fdm we can filter at rate at rate M/Q + + N=M/P; k = 1; + for i=1:N:nin + rx_filt(c,k) = (M/Q)*rx_baseband(st+i-1:dec_rate:st+i-1+Nfilter-1) * gt_alpha5_root(1:dec_rate:length(gt_alpha5_root))'; + k+=1; + end + end + + fdmdv.phase_rx = phase_rx; + fdmdv.rx_fdm_mem = rx_fdm_mem; +endfunction + + +% LPF and peak pick part of freq est, put in a function as we call it twice + +function [foff imax pilot_lpf_out S] = lpf_peak_pick(f, pilot_baseband, pilot_lpf, nin, do_fft) + M = f.M; + Npilotlpf = f.Npilotlpf; + Npilotbaseband = f.Npilotbaseband; + Npilotcoeff = f.Npilotcoeff; + Fs = f.Fs; + Mpilotfft = f.Mpilotfft; + pilot_coeff = f.pilot_coeff; + + % LPF cutoff 200Hz, so we can handle max +/- 200 Hz freq offset + + pilot_lpf(1:Npilotlpf-nin) = pilot_lpf(nin+1:Npilotlpf); + k = Npilotbaseband-nin+1;; + for i = Npilotlpf-nin+1:Npilotlpf + pilot_lpf(i) = pilot_baseband(k-Npilotcoeff+1:k) * pilot_coeff'; + k++; + end + + imax = 0; + foff = 0; + S = zeros(1, Mpilotfft); + + if do_fft + % decimate to improve DFT resolution, window and DFT + + Mpilot = Fs/(2*200); % calc decimation rate given new sample rate is twice LPF freq + h = hanning(Npilotlpf); + s = pilot_lpf(1:Mpilot:Npilotlpf) .* h(1:Mpilot:Npilotlpf)'; + s = [s zeros(1,Mpilotfft-Npilotlpf/Mpilot)]; + S = fft(s, Mpilotfft); + + % peak pick and convert to Hz + + [imax ix] = max(abs(S)); + r = 2*200/Mpilotfft; % maps FFT bin to frequency in Hz + + if ix > Mpilotfft/2 + foff = (ix - Mpilotfft - 1)*r; + else + foff = (ix - 1)*r; + endif + end + + pilot_lpf_out = pilot_lpf; + +endfunction + + +% Estimate frequency offset of FDM signal using BPSK pilot. This is quite +% sensitive to pilot tone level wrt other carriers + +function [foff S1 S2 f] = rx_est_freq_offset(f, rx_fdm, pilot, pilot_prev, nin, do_fft) + M = f.M; + Npilotbaseband = f.Npilotbaseband; + pilot_baseband1 = f.pilot_baseband1; + pilot_baseband2 = f.pilot_baseband2; + pilot_lpf1 = f.pilot_lpf1; + pilot_lpf2 = f.pilot_lpf2; + + % down convert latest nin samples of pilot by multiplying by ideal + % BPSK pilot signal we have generated locally. The peak of the DFT + % of the resulting signal is sensitive to the time shift between the + % received and local version of the pilot, so we do it twice at + % different time shifts and choose the maximum. + + pilot_baseband1(1:Npilotbaseband-nin) = pilot_baseband1(nin+1:Npilotbaseband); + pilot_baseband2(1:Npilotbaseband-nin) = pilot_baseband2(nin+1:Npilotbaseband); + for i=1:nin + pilot_baseband1(Npilotbaseband-nin+i) = rx_fdm(i) * conj(pilot(i)); + pilot_baseband2(Npilotbaseband-nin+i) = rx_fdm(i) * conj(pilot_prev(i)); + end + + [foff1 max1 pilot_lpf1 S1] = lpf_peak_pick(f, pilot_baseband1, pilot_lpf1, nin, do_fft); + [foff2 max2 pilot_lpf2 S2] = lpf_peak_pick(f, pilot_baseband2, pilot_lpf2, nin, do_fft); + + if max1 > max2 + foff = foff1; + else + foff = foff2; + end + + f.pilot_baseband1 = pilot_baseband1; + f.pilot_baseband2 = pilot_baseband2; + f.pilot_lpf1 = pilot_lpf1; + f.pilot_lpf2 = pilot_lpf2; +endfunction + + +% Estimate optimum timing offset, re-filter receive symbols + +function [rx_symbols rx_timing_M env fdmdv] = rx_est_timing(fdmdv, rx_filt, nin) + M = fdmdv.M; + Nt = fdmdv.Nt; + Nc = fdmdv.Nc; + rx_filter_mem_timing = fdmdv.rx_filter_mem_timing; + P = fdmdv.P; + Nfilter = fdmdv.Nfilter; + Nfiltertiming = fdmdv.Nfiltertiming; + + % nin adjust + % -------------------------------- + % 120 -1 (one less rate P sample) + % 160 0 (nominal) + % 200 1 (one more rate P sample) + + adjust = P - nin*P/M; + + % update buffer of Nt rate P filtered symbols + + rx_filter_mem_timing(:,1:(Nt-1)*P+adjust) = rx_filter_mem_timing(:,P+1-adjust:Nt*P); + rx_filter_mem_timing(:,(Nt-1)*P+1+adjust:Nt*P) = rx_filt(:,:); + + % sum envelopes of all carriers + + env = sum(abs(rx_filter_mem_timing(:,:))); % use all Nc+1 carriers for timing + %env = abs(rx_filter_mem_timing(Nc+1,:)); % just use BPSK pilot + [n m] = size(env); + + % The envelope has a frequency component at the symbol rate. The + % phase of this frequency component indicates the timing. So work out + % single DFT at frequency 2*pi/P + + x = env * exp(-j*2*pi*(0:m-1)/P)'; + + norm_rx_timing = angle(x)/(2*pi); + rx_timing = norm_rx_timing*P + P/4; + if (rx_timing > P) + rx_timing -= P; + end + if (rx_timing < -P) + rx_timing += P; + end + + % rx_filter_mem_timing contains Nt*P samples (Nt symbols at rate P), + % where Nt is odd. Lets use linear interpolation to resample in the + % centre of the timing estimation window + + rx_timing += floor(Nt/2)*P; + low_sample = floor(rx_timing); + fract = rx_timing - low_sample; + high_sample = ceil(rx_timing); + %printf("rx_timing: %f low_sample: %f high_sample: %f fract: %f\n", rx_timing, low_sample, high_sample, fract); + + rx_symbols = rx_filter_mem_timing(:,low_sample)*(1-fract) + rx_filter_mem_timing(:,high_sample)*fract; + % rx_symbols = rx_filter_mem_timing(:,high_sample+1); + + rx_timing_M = norm_rx_timing*M; + + fdmdv.rx_filter_mem_timing = rx_filter_mem_timing; +endfunction + + +% Experimental "feed forward" phase estimation function - estimates +% phase over a windows of Nph (e.g. Nph = 9) symbols. May not work +% well on HF channels but lets see. Has a phase ambiguity of m(pi/4) +% where m=0,1,2 which needs to be corrected outside of this function + +function [phase_offsets ferr f] = rx_est_phase(f, rx_symbols) + global rx_symbols_mem; + global prev_phase_offsets; + global phase_amb; + Nph = f.Nph; + Nc = f.Nc; + + % keep record of Nph symbols + + rx_symbols_mem(:,1:Nph-1) = rx_symbols_mem(:,2:Nph); + rx_symbols_mem(:,Nph) = rx_symbols; + + % estimate and correct phase offset based of modulation stripped samples + + phase_offsets = zeros(Nc+1,1); + for c=1:Nc+1 + + % rotate QPSK constellation to a single point + mod_stripped = abs(rx_symbols_mem(c,:)) .* exp(j*4*angle(rx_symbols_mem(c,:))); + + % find average phase offset, which will be on -pi/4 .. pi/4 + sum_real = sum(real(mod_stripped)); + sum_imag = sum(imag(mod_stripped)); + phase_offsets(c) = atan2(sum_imag, sum_real)/4; + + % determine if phase has jumped from - -> + + if (prev_phase_offsets(c) < -pi/8) && (phase_offsets(c) > pi/8) + phase_amb(c) -= pi/2; + if (phase_amb(c) < -pi) + phase_amb(c) += 2*pi; + end + end + + % determine if phase has jumped from + -> - + if (prev_phase_offsets(c) > pi/8) && (phase_offsets(c) < -pi/8) + phase_amb(c) += pi/2; + if (phase_amb(c) > pi) + phase_amb(c) -= 2*pi; + end + end + end + + ferr = mean(phase_offsets - prev_phase_offsets); + prev_phase_offsets = phase_offsets; + +endfunction + + +% convert symbols back to an array of bits + +function [rx_bits sync_bit f_err phase_difference] = psk_to_bits(f, prev_rx_symbols, rx_symbols, modulation) + Nc = f.Nc; + Nb = f.Nb; + + m4_binary_to_gray = [ + bin2dec("00") + bin2dec("01") + bin2dec("11") + bin2dec("10") + ]; + + m8_binary_to_gray = [ + bin2dec("000") + bin2dec("001") + bin2dec("011") + bin2dec("010") + bin2dec("110") + bin2dec("111") + bin2dec("101") + bin2dec("100") + ]; + + m = 2 .^ Nb; + assert((m == 4) || (m == 8)); + + phase_difference = zeros(Nc+1,1); + for c=1:Nc + norm = 1/(1E-6+abs(prev_rx_symbols(c))); + phase_difference(c) = rx_symbols(c) .* conj(prev_rx_symbols(c)) * norm; + end + + for c=1:Nc + phase_difference(c) *= exp(j*pi/4); + + if m == 4 + + % to get a good match between C and Octave during start up use same as C code + + d = phase_difference(c); + if (real(d) >= 0) && (imag(d) >= 0) + msb = 0; lsb = 0; + end + if (real(d) < 0) && (imag(d) >= 0) + msb = 0; lsb = 1; + end + if (real(d) < 0) && (imag(d) < 0) + msb = 1; lsb = 1; + end + if (real(d) >= 0) && (imag(d) < 0) + msb = 1; lsb = 0; + end + + rx_bits(2*(c-1)+1) = msb; + rx_bits(2*c) = lsb; + else + % determine index of constellation point received 0,1,...,m-1 + + index = floor(angle(phase_difference(c))*m/(2*pi) + 0.5); + + if index < 0 + index += m; + end + + % map to decimal version of bits encoded in symbol + + if m == 4 + bits_decimal = m4_binary_to_gray(index+1); + else + bits_decimal = m8_binary_to_gray(index+1); + end + + % convert back to an array of received bits + + for i=1:Nb + if bitand(bits_decimal, 2.^(Nb-i)) + rx_bits((c-1)*Nb+i) = 1; + else + rx_bits((c-1)*Nb+i) = 0; + end + end + end + end + + assert(length(rx_bits) == Nc*Nb); + + % Extract DBPSK encoded Sync bit + + norm = 1/(1E-6+abs(prev_rx_symbols(Nc+1))); + phase_difference(Nc+1) = rx_symbols(Nc+1) * conj(prev_rx_symbols(Nc+1)) * norm; + if (real(phase_difference(Nc+1)) < 0) + sync_bit = 1; + f_err = imag(phase_difference(Nc+1))*norm; % make f_err magnitude insensitive + else + sync_bit = 0; + f_err = -imag(phase_difference(Nc+1))*norm; + end + + % extra pi/4 rotation as we need for snr_update and scatter diagram + + phase_difference(Nc+1) *= exp(j*pi/4); + +endfunction + + +% given phase differences update estimates of signal and noise levels + +function [sig_est noise_est] = snr_update(f, sig_est, noise_est, phase_difference) + snr_coeff = f.snr_coeff; + Nc = f.Nc; + + % mag of each symbol is distance from origin, this gives us a + % vector of mags, one for each carrier. + + s = abs(phase_difference); + + % signal mag estimate for each carrier is a smoothed version + % of instantaneous magntitude, this gives us a vector of smoothed + % mag estimates, one for each carrier. + + sig_est = snr_coeff*sig_est + (1 - snr_coeff)*s; + + %printf("s: %f sig_est: %f snr_coeff: %f\n", s(1), sig_est(1), snr_coeff); + + % noise mag estimate is distance of current symbol from average + % location of that symbol. We reflect all symbols into the first + % quadrant for convenience. + + refl_symbols = abs(real(phase_difference)) + j*abs(imag(phase_difference)); + n = abs(exp(j*pi/4)*sig_est - refl_symbols); + + % noise mag estimate for each carrier is a smoothed version of + % instantaneous noise mag, this gives us a vector of smoothed + % noise power estimates, one for each carrier. + + noise_est = snr_coeff*noise_est + (1 - snr_coeff)*n; + +endfunction + + +% calculate current sig estimate for eeach carrier + +function snr_dB = calc_snr(f, sig_est, noise_est) + Rs = f.Rs; + + % find total signal power by summing power in all carriers + + S = sum(sig_est .^2); + SdB = 10*log10(S); + + % Average noise mag across all carriers and square to get an average + % noise power. This is an estimate of the noise power in Rs = 50Hz of + % BW (note for raised root cosine filters Rs is the noise BW of the + % filter) + + N50 = mean(noise_est).^2; + N50dB = 10*log10(N50); + + % Now multiply by (3000 Hz)/(50 Hz) to find the total noise power in + % 3000 Hz + + N3000dB = N50dB + 10*log10(3000/Rs); + + snr_dB = SdB - N3000dB; + +endfunction + + +% sets up test bits system. make sure rand('state', 1) has just beed called +% so we generate the right test_bits pattern! + +function f = init_test_bits(f) + f.Ntest_bits = f.Nc*f.Nb*4; % length of test sequence + f.test_bits = rand(1,f.Ntest_bits) > 0.5; % test pattern of bits + f.current_test_bit = 1; + f.rx_test_bits_mem = zeros(1,f.Ntest_bits); +endfunction + + +% returns nbits from a repeating sequence of random data + +function [bits f] = get_test_bits(f, nbits) + + for i=1:nbits + bits(i) = f.test_bits(f.current_test_bit++); + + if (f.current_test_bit > f.Ntest_bits) + f.current_test_bit = 1; + endif + end + +endfunction + + +% Accepts nbits from rx and attempts to sync with test_bits sequence. +% if sync OK measures bit errors + +function [sync bit_errors error_pattern f] = put_test_bits(f, test_bits, rx_bits) + Ntest_bits = f.Ntest_bits; + rx_test_bits_mem = f.rx_test_bits_mem; + + % Append to our memory + + [m n] = size(rx_bits); + f.rx_test_bits_mem(1:f.Ntest_bits-n) = freedv.rx_test_bits_mem(n+1:f.Ntest_bits); + f.rx_test_bits_mem(f.Ntest_bits-n+1:f.Ntest_bits) = rx_bits; + + % see how many bit errors we get when checked against test sequence + + error_pattern = xor(test_bits, f.rx_test_bits_mem); + bit_errors = sum(error_pattern); + + % if less than a thresh we are aligned and in sync with test sequence + + ber = bit_errors/f.Ntest_bits; + + sync = 0; + if (ber < 0.2) + sync = 1; + endif +endfunction + +% Generate M samples of DBPSK pilot signal for Freq offset estimation + +function [pilot_fdm bit symbol filter_mem phase] = generate_pilot_fdm(f, bit, symbol, filter_mem, phase, freq) + M = f.M; + Nfilter = f.Nfilter; + gt_alpha5_root = f.gt_alpha5_root; + + % +1 -1 +1 -1 DBPSK sync carrier, once filtered becomes two spectral + % lines at +/- Rs/2 + + if bit + symbol = -symbol; + else + symbol = symbol; + end + if bit + bit = 0; + else + bit = 1; + end + + % filter DPSK symbol to create M baseband samples + + filter_mem(Nfilter) = (sqrt(2)/2)*symbol; + for i=1:M + tx_baseband(i) = M*filter_mem(M:M:Nfilter) * gt_alpha5_root(M-i+1:M:Nfilter)'; + end + filter_mem(1:Nfilter-M) = filter_mem(M+1:Nfilter); + filter_mem(Nfilter-M+1:Nfilter) = zeros(1,M); + + % upconvert + + for i=1:M + phase = phase * freq; + pilot_fdm(i) = sqrt(2)*2*tx_baseband(i)*phase; + end + +endfunction + + +% Generate a 4M sample vector of DBPSK pilot signal. As the pilot signal +% is periodic in 4M samples we can then use this vector as a look up table +% for pilot signal generation in the demod. + +function pilot_lut = generate_pilot_lut(f) + Nc = f.Nc; + Nfilter = f.Nfilter; + M = f.M; + freq = f.freq; + + % pilot states + + pilot_rx_bit = 0; + pilot_symbol = sqrt(2); + pilot_freq = freq(Nc+1); + pilot_phase = 1; + pilot_filter_mem = zeros(1, Nfilter); + %prev_pilot = zeros(M,1); + + pilot_lut = []; + + F=8; + + for fr=1:F + [pilot pilot_rx_bit pilot_symbol pilot_filter_mem pilot_phase] = generate_pilot_fdm(f, pilot_rx_bit, pilot_symbol, pilot_filter_mem, pilot_phase, pilot_freq); + %prev_pilot = pilot; + pilot_lut = [pilot_lut pilot]; + end + + % discard first 4 symbols as filter memory is filling, just keep last + % four symbols + + pilot_lut = pilot_lut(4*M+1:M*F); + +endfunction + + +% grab next pilot samples for freq offset estimation at demod + +function [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(f, pilot_lut_index, prev_pilot_lut_index, nin) + M = f.M; + pilot_lut = f.pilot_lut; + + for i=1:nin + pilot(i) = pilot_lut(pilot_lut_index); + pilot_lut_index++; + if pilot_lut_index > 4*M + pilot_lut_index = 1; + end + prev_pilot(i) = pilot_lut(prev_pilot_lut_index); + prev_pilot_lut_index++; + if prev_pilot_lut_index > 4*M + prev_pilot_lut_index = 1; + end + end +endfunction + + +% freq offset state machine. Moves between acquire and track states based +% on BPSK pilot sequence. Freq offset estimator occasionally makes mistakes +% when used continuously. So we use it until we have acquired the BPSK pilot, +% then switch to a more robust tracking algorithm. If we lose sync we switch +% back to acquire mode for fast-requisition. + +function [sync reliable_sync_bit state timer sync_mem] = freq_state(f, sync_bit, state, timer, sync_mem) + Nsync_mem = f.Nsync_mem; + sync_uw = f.sync_uw; + + % look for 6 symbol (120ms) 010101 of sync sequence + + unique_word = 0; + for i=1:Nsync_mem-1 + sync_mem(i) = sync_mem(i+1); + end + sync_mem(Nsync_mem) = 1 - 2*sync_bit; + corr = 0; + for i=1:Nsync_mem + corr += sync_mem(i)*sync_uw(i); + end + if abs(corr) == Nsync_mem + unique_word = 1; + end + reliable_sync_bit = (corr == Nsync_mem); + + % iterate state machine + + next_state = state; + if state == 0 + if unique_word + next_state = 1; + timer = 0; + end + end + if state == 1 + if unique_word + timer++; + if timer == 25 % sync has been good for 500ms + next_state = 2; + end + else + next_state = 0; + end + end + if state == 2 % good sync state + if unique_word == 0 + timer = 0; + next_state = 3; + end + end + if state == 3 % tenative bad state, but could be a fade + if unique_word + next_state = 2; + else + timer++; + if timer == 50 % wait for 1000ms in case sync comes back + next_state = 0; + end + end + end + + %printf("corr: % -d state: %d next_state: %d uw: %d timer: %d\n", corr, state, next_state, unique_word, timer); + state = next_state; + + if state + sync = 1; + else + sync = 0; + end +endfunction + + +% complex freq shifting helper function + +function [out phase] = freq_shift(in, freqHz, Fs, phase) + freq_rect = exp(j*2*pi*freqHz/Fs); + + out = zeros(1, length(in)); + for r=1:length(in) + phase *= freq_rect; + out(r) = in(r)*phase; + end + + mag = abs(phase); + phase /= mag; +endfunction + + +% Save test bits to a text file in the form of a C array + +function test_bits_file(filename) + global test_bits; + global Ntest_bits; + + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by test_bits_file() Octave function */\n\n"); + fprintf(f,"const int test_bits[]={\n"); + for m=1:Ntest_bits-1 + fprintf(f," %d,\n",test_bits(m)); + endfor + fprintf(f," %d\n};\n",test_bits(Ntest_bits)); + fclose(f); +endfunction + + +% Saves RN filter coeffs to a text file in the form of a C array + +function rn_file(gt_alpha5_root, filename) + Nfilter = length(gt_alpha5_root); + + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by rn_file() Octave function */\n\n"); + fprintf(f,"const float gt_alpha5_root[]={\n"); + for m=1:Nfilter-1 + fprintf(f," %g,\n",gt_alpha5_root(m)); + endfor + fprintf(f," %g\n};\n",gt_alpha5_root(Nfilter)); + fclose(f); +endfunction + + +% Saves rx decimation filter coeffs to a text file in the form of a C array + +function rxdec_file(fdmdv, filename) + rxdec_coeff = fdmdv.rxdec_coeff; + Nrxdec = fdmdv.Nrxdec; + + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by rxdec_file() Octave function */\n\n"); + fprintf(f,"const float rxdec_coeff[]={\n"); + for m=1:Nrxdec-1 + fprintf(f," %g,\n",rxdec_coeff(m)); + endfor + fprintf(f," %g\n};\n",rxdec_coeff(Nrxdec)); + fclose(f); +endfunction + + +function pilot_coeff_file(fdmdv, filename) + pilot_coeff = fdmdv.pilot_coeff; + Npilotcoeff = fdmdv.Npilotcoeff; + + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by pilot_coeff_file() Octave function */\n\n"); + fprintf(f,"const float pilot_coeff[]={\n"); + for m=1:Npilotcoeff-1 + fprintf(f," %g,\n",pilot_coeff(m)); + endfor + fprintf(f," %g\n};\n",pilot_coeff(Npilotcoeff)); + fclose(f); +endfunction + + +% Saves hanning window coeffs to a text file in the form of a C array + +function hanning_file(fdmdv, filename) + Npilotlpf = fdmdv.Npilotlpf; + + h = hanning(Npilotlpf); + + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by hanning_file() Octave function */\n\n"); + fprintf(f,"const float hanning[]={\n"); + for m=1:Npilotlpf-1 + fprintf(f," %g,\n", h(m)); + endfor + fprintf(f," %g\n};\n", h(Npilotlpf)); + fclose(f); +endfunction + + +function png_file(fig, pngfilename) + figure(fig); + + pngname = sprintf("%s.png",pngfilename); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_large.png",pngfilename); + print(pngname, '-dpng', "-S800,600") +endfunction + + +% dump rx_bits in hex + +function dump_bits(rx_bits) + + % pack into bytes, MSB first + + packed = zeros(1,floor(length(rx_bits)+7)/8); + bit = 7; byte = 1; + for i=1:length(rx_bits) + packed(byte) = bitor(packed(byte), bitshift(rx_bits(i),bit)); + bit--; + if (bit < 0) + bit = 7; + byte++; + end + end + + for i=1:length(packed) + printf("0x%02x ", packed(i)); + end + printf("\n"); + +endfunction + diff --git a/codec2/branches/0.7/octave/fdmdv_demod.m b/codec2/branches/0.7/octave/fdmdv_demod.m new file mode 100644 index 00000000..6b5c0a23 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_demod.m @@ -0,0 +1,353 @@ +% fdmdv_demod.m +% +% Demodulator function for FDMDV modem (Octave version). Requires +% 8kHz sample rate raw files as input +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +function fdmdv_demod(rawfilename, nbits, NumCarriers, errorpatternfilename, symbolfilename) + + fdmdv; % include modem code + + modulation = 'dqpsk'; + + fin = fopen(rawfilename, "rb"); + gain = 1000; + frames = nbits/(Nc*Nb); + + prev_rx_symbols = ones(Nc+1,1); + foff_phase_rect = 1; + + % BER stats + + total_bit_errors = 0; + total_bits = 0; + bit_errors_log = []; + sync_log = []; + test_frame_sync_log = []; + test_frame_sync_state = 0; + error_pattern_log = []; + + % SNR states + + sig_est = zeros(Nc+1,1); + noise_est = zeros(Nc+1,1); + + % logs of various states for plotting + + rx_symbols_log = []; + rx_timing_log = []; + foff_coarse_log = []; + foff_log = []; + rx_fdm_log = []; + snr_est_log = []; + + % misc states + + nin = M; % timing correction for sample rate differences + foff = 0; + + fest_state = 0; + fest_timer = 0; + sync_mem = zeros(1,Nsync_mem); + sync = 0; + sync_log = []; + + % spectrum states + + Nspec=1024; + spec_mem=zeros(1,Nspec); + SdB = zeros(1,Nspec); + + % optionally save output symbols + + if nargin == 5 + fm = fopen(symbolfilename,"wb"); + dual_rx_symbols = zeros(1, 2*Nc); + dual_rx_bits = zeros(1,2*Nc*Nb); + end + + % Main loop ---------------------------------------------------- + + for f=1:frames + + % obtain nin samples of the test input signal + + for i=1:nin + rx_fdm(i) = fread(fin, 1, "short")/gain; + end + + rx_fdm_log = [rx_fdm_log rx_fdm(1:nin)]; + + % update spectrum + + l=length(rx_fdm); + spec_mem(1:Nspec-l) = spec_mem(l+1:Nspec); + spec_mem(Nspec-l+1:Nspec) = rx_fdm; + S=fft(spec_mem.*hanning(Nspec)',Nspec); + SdB = 0.9*SdB + 0.1*20*log10(abs(S)); + + % shift down to complex baseband + + for i=1:nin + fbb_phase_rx = fbb_phase_rx*fbb_rect'; + rx_fdm(i) = rx_fdm(i)*fbb_phase_rx; + end + mag = abs(fbb_phase_rx); + fbb_phase_rx /= mag; + + % frequency offset estimation and correction + + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); + [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin, !sync ); + + if sync == 0 + foff = foff_coarse; + end + foff_coarse_log = [foff_coarse_log foff_coarse]; + + foff_rect = exp(j*2*pi*foff/Fs); + + for i=1:nin + foff_phase_rect *= foff_rect'; + rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect; + end + + % baseband processing + + rx_fdm_filter = rxdec_filter(rx_fdm_fcorr, nin); + rx_filt = down_convert_and_rx_filter(rx_fdm_filter, nin, M/Q); + [rx_symbols rx_timing] = rx_est_timing(rx_filt, nin); + rx_timing_log = [rx_timing_log rx_timing]; + + nin = M; + if rx_timing > 2*M/P + nin += M/P; + end + if rx_timing < 0; + nin -= M/P; + end + + rx_symbols_log = [rx_symbols_log rx_symbols.*conj(prev_rx_symbols./abs(prev_rx_symbols))*exp(j*pi/4)]; + [rx_bits sync_bit f_err pd] = psk_to_bits(prev_rx_symbols, rx_symbols, modulation); + + % optionally save output symbols + + if (nargin == 5) + + % this free runs, and is reset by an "entered sync" state + + if (sync_track == 0) + sync_track = 1; + else + sync_track = 0; + end + + if (track == 1) && (sync_track == 1) + dual_rx_symbols(Nc+1:2*Nc) = rx_symbols(1:Nc).*conj(prev_rx_symbols(1:Nc)./abs(prev_rx_symbols(1:Nc))); + dual_rx_symbols_float32 = []; k = 1; + for i=1:2*Nc + dual_rx_symbols_float32(k++) = real(dual_rx_symbols(i)); + dual_rx_symbols_float32(k++) = imag(dual_rx_symbols(i)); + end + fwrite(fm, dual_rx_symbols_float32, "float32"); + dual_rx_bits(Nc*Nb+1:2*Nc*Nb) = rx_bits; + %dump_bits(dual_rx_bits); + else + dual_rx_symbols(1:Nc) = rx_symbols(1:Nc).*conj(prev_rx_symbols(1:Nc)./abs(prev_rx_symbols(1:Nc))); + dual_rx_bits(1:Nc*Nb) = rx_bits; + end + end + + % update some states + + prev_rx_symbols = rx_symbols; + [sig_est noise_est] = snr_update(sig_est, noise_est, pd); + snr_est = calc_snr(sig_est, noise_est); + snr_est_log = [snr_est_log snr_est]; + foff -= 0.5*f_err; + foff_log = [foff_log foff]; + + % freq est state machine + + [sync reliable_sync_bit fest_state fest_timer sync_mem] = freq_state(sync_bit, fest_state, fest_timer, sync_mem); + sync_log = [sync_log sync]; + + % count bit errors if we find a test frame + + [test_frame_sync bit_errors error_pattern] = put_test_bits(test_bits, rx_bits); + if (test_frame_sync == 1) + total_bit_errors = total_bit_errors + bit_errors; + total_bits = total_bits + Ntest_bits; + bit_errors_log = [bit_errors_log bit_errors/Ntest_bits]; + else + bit_errors_log = [bit_errors_log 0]; + end + + % test frame sync state machine, just for more informative plots + + next_test_frame_sync_state = test_frame_sync_state; + if (test_frame_sync_state == 0) + if (test_frame_sync == 1) + next_test_frame_sync_state = 1; + test_frame_count = 0; + end + end + + if (test_frame_sync_state == 1) + % we only expect another test_frame_sync pulse every 4 symbols + test_frame_count++; + if (test_frame_count == 4) + test_frame_count = 0; + if ((test_frame_sync == 0)) + next_test_frame_sync_state = 0; + else + error_pattern_log = [error_pattern_log error_pattern]; + end + end + end + + test_frame_sync_state = next_test_frame_sync_state; + test_frame_sync_log = [test_frame_sync_log test_frame_sync_state]; + end + + if nargin == 5 + fclose(fm); + etfilename = strcat(strtok(symbolfilename,"."),"_et.bin"); + fet = fopen(etfilename, "wb"); + fwrite(fet, entered_track_log, "short"); + fclose(fet); + end + + % --------------------------------------------------------------------- + % Print Stats + % --------------------------------------------------------------------- + + % Peak to Average Power Ratio calcs from http://www.dsplog.com + + papr = max(rx_fdm_log.*conj(rx_fdm_log)) / mean(rx_fdm_log.*conj(rx_fdm_log)); + papr_dB = 10*log10(papr); + + ber = total_bit_errors / total_bits; + printf("%d bits %d errors BER: %1.4f PAPR(rx): %1.2f dB\n",total_bits, total_bit_errors, ber, papr_dB); + + % --------------------------------------------------------------------- + % Plots + % --------------------------------------------------------------------- + + xt = (1:frames)/Rs; + secs = frames/Rs; + + figure(1) + clf; + [n m] = size(rx_symbols_log); + plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+') + axis([-2 2 -2 2]); + title('Scatter Diagram'); + + figure(2) + clf; + subplot(211) + plot(xt, rx_timing_log) + title('timing offset (samples)'); + subplot(212) + plot(xt, foff_log, '-;freq offset;') + hold on; + plot(xt, sync_log*75, 'r;course-fine;'); + hold off; + title('Freq offset (Hz)'); + grid + + figure(3) + clf; + spec(rx_fdm_log,8000); + + figure(4) + clf; + subplot(311) + stem(xt, sync_log) + axis([0 secs 0 1.5]); + title('BPSK Sync') + subplot(312) + stem(xt, bit_errors_log); + title('Bit Errors for test frames') + subplot(313) + plot(xt, test_frame_sync_log); + axis([0 secs 0 1.5]); + title('Test Frame Sync') + + figure(5) + clf; + subplot(211); + plot(xt, snr_est_log); + title('SNR Estimates') + subplot(212) + snrdB_pc = 20*log10(sig_est(1:Nc+1)) - 20*log10(noise_est(1:Nc+1)); + bar(snrdB_pc(1:Nc) - mean(snrdB_pc(1:Nc))) + axis([0 Nc+1 -3 3]); + + figure(6) + clf; + hold on; + lep = length(error_pattern_log); + if lep != 0 + for p=1:Nc + plot(p + 0.25*error_pattern_log((p-1)*2+1:Nc*Nb:lep)); + plot(0.30 + p + 0.25*error_pattern_log(p*2:Nc*Nb:lep),'r') + end + hold off; + axis([1 lep/(Nc*Nb) 0 Nc]) + end + + figure(7) + clf; + subplot(211) + [a b] = size(rx_fdm_log); + xt1 = (1:b)/Fs; + plot(xt1, rx_fdm_log); + title('Rx FDM Signal'); + subplot(212) + plot((0:Nspec/2-1)*Fs/Nspec, SdB(1:Nspec/2) - 20*log10(Nspec/2)) + axis([0 Fs/2 -40 0]) + grid + title('FDM Rx Spectrum'); + +if 0 + % interleaving tests + + load ../unittest/inter560.txt + lep = length(error_pattern_log); + lep = floor(lep/560)*560; + error_pattern_log_inter = zeros(1,lep); + for i=1:560:lep + for j=1:560 + %printf("i: %4d j: %4d inter560(j): %4d\n", i,j,inter560(j)); + index = inter560(j); + error_pattern_log_inter(i-1+index+1) = error_pattern_log(i-1+j); + end + end + + figure(8) + clf; + hold on; + for p=1:Nc + plot(p + 0.25*error_pattern_log_inter((p-1)*2+1:Nc*Nb:lep)); + plot(0.30 + p + 0.25*error_pattern_log_inter(p*2:Nc*Nb:lep),'r') + end + hold off; + axis([1 lep/(Nc*Nb) 0 Nc]) +end + + % optionally save error pattern file + + if nargin == 4 + fout = fopen(errorpatternfilename, "wb"); + fwrite(fout, error_pattern_log, "short"); + fclose(fout); + end + + +endfunction diff --git a/codec2/branches/0.7/octave/fdmdv_demod_c.m b/codec2/branches/0.7/octave/fdmdv_demod_c.m new file mode 100644 index 00000000..b5c75334 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_demod_c.m @@ -0,0 +1,132 @@ +% fdmdv_demod_c.m +% +% Plots Octave dump file information from C FDMDV demodulator program, +% to give a similar set of plots to fdmdv_demod.m. Useful for off +% line analysis of demod performance. +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +function fdmdv_demod_c(dumpfilename, bits, NumCarriers) + + fdmdv; % include modem code + + frames = bits/(Nc*Nb); + + load(dumpfilename); + + % BER stats + + total_bit_errors = 0; + total_bits = 0; + bit_errors_log = []; + sync_log = []; + test_frame_sync_log = []; + test_frame_sync_state = 0; + + % Run thru received bits to look for test pattern + + bits_per_frame = Nc*Nb; + + for f=1:frames + + rx_bits = rx_bits_log_c((f-1)*bits_per_frame+1:f*bits_per_frame); + + % count bit errors if we find a test frame + + [test_frame_sync bit_errors] = put_test_bits(test_bits, rx_bits); + if (test_frame_sync == 1) + total_bit_errors = total_bit_errors + bit_errors; + total_bits = total_bits + Ntest_bits; + bit_errors_log = [bit_errors_log bit_errors/Ntest_bits]; + else + bit_errors_log = [bit_errors_log 0]; + end + + % test frame sync state machine, just for more informative plots + + next_test_frame_sync_state = test_frame_sync_state; + if (test_frame_sync_state == 0) + if (test_frame_sync == 1) + next_test_frame_sync_state = 1; + test_frame_count = 0; + end + end + + if (test_frame_sync_state == 1) + % we only expect another test_frame_sync pulse every 4 symbols + test_frame_count++; + if (test_frame_count == 4) + test_frame_count = 0; + if ((test_frame_sync == 0)) + next_test_frame_sync_state = 0; + end + end + end + test_frame_sync_state = next_test_frame_sync_state; + test_frame_sync_log = [test_frame_sync_log test_frame_sync_state]; + end + + ber = total_bit_errors / total_bits; + printf("%d bits %d errors BER: %1.4f\n",total_bits, total_bit_errors, ber); + + % --------------------------------------------------------------------- + % Plots + % --------------------------------------------------------------------- + + xt = (1:frames)/Rs; + secs = frames/Rs; + + figure(1) + clf; + plot(real(rx_symbols_log_c(1:Nc+1,15:frames)),imag(rx_symbols_log_c(1:Nc+1,15:frames)),'+') + %plot(real(rx_symbols_log_c(Nc+1,15:frames)),imag(rx_symbols_log_c(Nc+1,15:frames)),'+') + axis([-2 2 -2 2]); + title('Scatter Diagram'); + + figure(2) + clf; + subplot(211) + plot(xt, rx_timing_log_c(1:frames)) + title('timing offset (samples)'); + subplot(212) + plot(xt, foff_log_c(1:frames), '-;freq offset;') + hold on; + plot(xt, sync_log_c(1:frames)*75, 'r;course-fine;'); + hold off; + title('Freq offset (Hz)'); + grid + + figure(3) + clf; + subplot(211) + b = M*frames; + xt1 = (1:b)/Fs; + plot(xt1, rx_fdm_log_c(1:b)); + title('Rx FDM Signal'); + subplot(212) + spec(rx_fdm_log_c(1:b),8000); + title('FDM Rx Spectrogram'); + + figure(4) + clf; + subplot(311) + stem(xt, sync_bit_log_c(1:frames)) + axis([0 secs 0 1.5]); + title('BPSK Sync') + subplot(312) + stem(xt, bit_errors_log); + title('Bit Errors for test frames') + subplot(313) + plot(xt, test_frame_sync_log); + axis([0 secs 0 1.5]); + title('Test Frame Sync') + + figure(5) + clf; + plot(xt, snr_est_log_c(1:frames)); + title('SNR Estimates') + +endfunction diff --git a/codec2/branches/0.7/octave/fdmdv_demod_coh.m b/codec2/branches/0.7/octave/fdmdv_demod_coh.m new file mode 100644 index 00000000..94b08802 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_demod_coh.m @@ -0,0 +1,253 @@ +% fdmdv_demod_coh.m +% +% Demodulator function for FDMDV modem (Octave version). Requires +% 8kHz sample rate raw files as input. This version uses experimental +% psuedo coherent demodulation. +% +% Copyright David Rowe 2013 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +function fdmdv_demod_coh(rawfilename, nbits, pngname) + + fdmdv; % include modem code + + modulation = 'dqpsk'; + + fin = fopen(rawfilename, "rb"); + gain = 1000; + frames = nbits/(Nc*Nb); + + prev_rx_symbols = ones(Nc+1,1); + foff_phase = 1; + + % BER stats + + total_bit_errors = 0; + total_bits = 0; + bit_errors_log = []; + sync_log = []; + test_frame_sync_log = []; + test_frame_sync_state = 0; + + % SNR states + + sig_est = zeros(Nc+1,1); + noise_est = zeros(Nc+1,1); + + % logs of various states for plotting + + rx_symbols_log = []; + rx_timing_log = []; + foff_log = []; + rx_fdm_log = []; + snr_est_log = []; + + % misc states + + nin = M; % timing correction for sample rate differences + foff = 0; + track_log = []; + track = 0; + fest_state = 0; + + % psuedo coherent demod states + + rx_symbols_ph_log = []; + prev_rx_symbols_ph = ones(Nc+1,1); + rx_phase_offsets_log = []; + phase_amb_log = []; + + % Main loop ---------------------------------------------------- + + for f=1:frames + + % obtain nin samples of the test input signal + + for i=1:nin + rx_fdm(i) = fread(fin, 1, "short")/gain; + end + + rx_fdm_log = [rx_fdm_log rx_fdm(1:nin)]; + + % frequency offset estimation and correction + + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin); + [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin); + + if track == 0 + foff = foff_coarse; + end + foff_log = [ foff_log foff ]; + foff_rect = exp(j*2*pi*foff/Fs); + + for i=1:nin + foff_phase *= foff_rect'; + rx_fdm(i) = rx_fdm(i)*foff_phase; + end + + % baseband processing + + rx_baseband = fdm_downconvert(rx_fdm, nin); + rx_filt = rx_filter(rx_baseband, nin); + + [rx_symbols rx_timing] = rx_est_timing(rx_filt, rx_baseband, nin); + rx_timing_log = [rx_timing_log rx_timing]; + + nin = M; + if rx_timing > 2*M/P + nin += M/P; + end + if rx_timing < 0; + nin -= M/P; + end + + rx_symbols_log = [rx_symbols_log rx_symbols.*(conj(prev_rx_symbols)./abs(prev_rx_symbols))*exp(j*pi/4)]; + + % coherent phase offset estimation ------------------------------------ + + [rx_phase_offsets ferr] = rx_est_phase(rx_symbols); + rx_phase_offsets_log = [rx_phase_offsets_log rx_phase_offsets]; + phase_amb_log = [phase_amb_log phase_amb]; + rx_symbols_ph = rx_symbols_mem(:,floor(Nph/2)+1) .* exp(-j*(rx_phase_offsets + phase_amb)); + rx_symbols_ph_log = [rx_symbols_ph_log rx_symbols_ph .* exp(j*pi/4)]; + rx_symbols_ph = -1 + 2*(real(rx_symbols_ph .* exp(j*pi/4)) > 0) + j*(-1 + 2*(imag(rx_symbols_ph .* exp(j*pi/4)) > 0)); + + % Std differential (used for freq offset est and BPSK sync) and psuedo coherent detection ----------------------- + + [rx_bits_unused sync f_err pd ] = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation); + [rx_bits sync_unused ferr_unused pd_unused] = qpsk_to_bits(prev_rx_symbols_ph, rx_symbols_ph, 'dqpsk'); + + foff -= 0.5*f_err; + prev_rx_symbols = rx_symbols; + prev_rx_symbols_ph = rx_symbols_ph; + sync_log = [sync_log sync]; + + [sig_est noise_est] = snr_update(sig_est, noise_est, pd); + snr_est = calc_snr(sig_est, noise_est); + snr_est_log = [snr_est_log snr_est]; + + % freq est state machine + + [track fest_state] = freq_state(sync, fest_state); + track_log = [track_log track]; + + % count bit errors if we find a test frame + + [test_frame_sync bit_errors] = put_test_bits(test_bits, rx_bits); + if (test_frame_sync == 1) + total_bit_errors = total_bit_errors + bit_errors; + total_bits = total_bits + Ntest_bits; + bit_errors_log = [bit_errors_log bit_errors/Ntest_bits]; + else + bit_errors_log = [bit_errors_log 0]; + end + + % test frame sync state machine, just for more informative plots + + next_test_frame_sync_state = test_frame_sync_state; + if (test_frame_sync_state == 0) + if (test_frame_sync == 1) + next_test_frame_sync_state = 1; + test_frame_count = 0; + end + end + + if (test_frame_sync_state == 1) + % we only expect another test_frame_sync pulse every 4 symbols + test_frame_count++; + if (test_frame_count == 4) + test_frame_count = 0; + if ((test_frame_sync == 0)) + next_test_frame_sync_state = 0; + end + end + end + test_frame_sync_state = next_test_frame_sync_state; + test_frame_sync_log = [test_frame_sync_log test_frame_sync_state]; + + end + + % --------------------------------------------------------------------- + % Print Stats + % --------------------------------------------------------------------- + + ber = total_bit_errors / total_bits; + + printf("%d bits %d errors BER: %1.4f\n",total_bits, total_bit_errors, ber); + + % --------------------------------------------------------------------- + % Plots + % --------------------------------------------------------------------- + + xt = (1:frames)/Rs; + secs = frames/Rs; + + figure(1) + clf; + [n m] = size(rx_symbols_log); + plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+') + axis([-2 2 -2 2]); + title('Scatter Diagram'); + + figure(2) + clf; + subplot(211) + plot(xt, rx_timing_log) + title('timing offset (samples)'); + subplot(212) + plot(xt, foff_log, '-;freq offset;') + hold on; + plot(xt, track_log*75, 'r;course-fine;'); + hold off; + title('Freq offset (Hz)'); + grid + + figure(3) + clf; + subplot(211) + [a b] = size(rx_fdm_log); + xt1 = (1:b)/Fs; + plot(xt1, rx_fdm_log); + title('Rx FDM Signal'); + subplot(212) + spec(rx_fdm_log,8000); + title('FDM Rx Spectrogram'); + + figure(4) + clf; + subplot(311) + stem(xt, sync_log) + axis([0 secs 0 1.5]); + title('BPSK Sync') + subplot(312) + stem(xt, bit_errors_log); + title('Bit Errors for test frames') + subplot(313) + plot(xt, test_frame_sync_log); + axis([0 secs 0 1.5]); + title('Test Frame Sync') + + figure(5) + clf; + plot(xt, snr_est_log); + title('SNR Estimates') + + figure(6) + clf; + [n m] = size(rx_symbols_ph_log); + plot(real(rx_symbols_ph_log(1:Nc+1,15:m)),imag(rx_symbols_ph_log(1:Nc+1,15:m)),'+') + %plot(real(rx_symbols_ph_log(2,15:m)),imag(rx_symbols_ph_log(2,15:m)),'+') + axis([-2 2 -2 2]); + title('Scatter Diagram - after phase correction'); + + figure(7) + clf; + subplot(211) + plot(rx_phase_offsets_log(1,:)) + subplot(212) + plot(phase_amb_log(1,:)) + title('Rx Phase Offset Est') + +endfunction diff --git a/codec2/branches/0.7/octave/fdmdv_mod.m b/codec2/branches/0.7/octave/fdmdv_mod.m new file mode 100644 index 00000000..8d132264 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_mod.m @@ -0,0 +1,32 @@ +% fdmdv_mod.m +% +% Modulator function for FDMDV modem, uses test frames as input and +% outputs a raw file of 16 bit shorts at a sample rate of 8 kHz. +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +function tx_fdm = fdmdv_mod(rawfilename, nbits) + + fdmdv; % include modem code + + frames = floor(nbits/(Nc*Nb)) + tx_fdm = []; + gain = 1000; % Scale up to 16 bit shorts + prev_tx_symbols = ones(Nc+1,1); prev_tx_symbols(Nc+1) = 2; + + for i=1:frames + tx_bits = get_test_bits(Nc*Nb); + tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits,'dqpsk'); + prev_tx_symbols = tx_symbols; + tx_baseband = tx_filter(tx_symbols); + tx_fdm = [tx_fdm real(fdm_upconvert(tx_baseband))]; + end + + tx_fdm *= gain; + fout = fopen(rawfilename,"wb"); + fwrite(fout, tx_fdm, "short"); + fclose(fout); +endfunction diff --git a/codec2/branches/0.7/octave/fdmdv_sweep.m b/codec2/branches/0.7/octave/fdmdv_sweep.m new file mode 100644 index 00000000..fd617431 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_sweep.m @@ -0,0 +1,30 @@ +% fdmdv_sweep.m +% David Rowe Feb 2013 +% Produces a raw file that sweeps between 1000 and 2000 Hz to test freq +% response of transmitters. + +secs=10; +fmin=1000; +fmax=2000; +Fs=8000; +rms = 4200; % roughly RMS value of fdmdv signal +amp = sqrt(2)*rms; +nsamples=Fs*secs; +theta = 0; +s=zeros(1,nsamples); + +for i=1:nsamples + f(i) = fmin + i*(fmax-fmin)/nsamples; + w = 2*pi*f(i)/Fs; + theta += w; + theta -= 2*pi*floor(theta/(2*pi)); + s(i) = amp*cos(theta); +end + +figure(1) +clf +plot(s(1:100)); +fout = fopen("1k_2k_sweep.raw", "wb"); +fwrite(fout, s, "short"); +fclose(fout); + diff --git a/codec2/branches/0.7/octave/fdmdv_ut.m b/codec2/branches/0.7/octave/fdmdv_ut.m new file mode 100644 index 00000000..3ee5b4de --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_ut.m @@ -0,0 +1,352 @@ +% fdmdv_ut.m +% +% Unit Test program for FDMDV modem. Useful for general development as it has +% both tx and rx sides, and basic AWGN channel simulation. +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +fdmdv; % load modem code + +% Simulation Parameters -------------------------------------- + +frames = 100; +EbNo_dB = 6.3; +Foff_hz = -100; +modulation = 'dqpsk'; +hpa_clip = 150; + +% ------------------------------------------------------------ + +more off; +tx_filt = zeros(Nc,M); +rx_symbols_log = []; +rx_phase_log = 0; +rx_timing_log = 0; +tx_pwr = 0; +noise_pwr = 0; +rx_fdm_log = []; +rx_baseband_log = []; +rx_bits_offset = zeros(Nc*Nb*2); +prev_tx_symbols = ones(Nc+1,1); prev_tx_symbols(Nc+1) = 2; +prev_rx_symbols = ones(Nc+1,1); +ferr = 0; +foff = 0; +foff_log = []; +tx_baseband_log = []; +tx_fdm_log = []; + +% BER stats + +total_bit_errors = 0; +total_bits = 0; +bit_errors_log = []; +sync_bit_log = []; +test_frame_sync_log = []; +test_frame_sync_state = 0; + +% SNR estimation states + +sig_est = zeros(Nc+1,1); +noise_est = zeros(Nc+1,1); + +% fixed delay simuation + +Ndelay = M+20; +rx_fdm_delay = zeros(Ndelay,1); + +% --------------------------------------------------------------------- +% Eb/No calculations. We need to work out Eb/No for each FDM carrier. +% Total power is sum of power in all FDM carriers +% --------------------------------------------------------------------- + +C = 1; % power of each FDM carrier (energy/sample). Total Carrier power should = Nc*C = Nc +N = 1; % total noise power (energy/sample) of noise source across entire bandwidth + +% Eb = Carrier power * symbol time / (bits/symbol) +% = C *(1/Rs) / Nb +Eb_dB = 10*log10(C) - 10*log10(Rs) - 10*log10(Nb); + +No_dBHz = Eb_dB - EbNo_dB; + +% Noise power = Noise spectral density * bandwidth +% Noise power = Noise spectral density * Fs/2 for real signals +N_dB = No_dBHz + 10*log10(Fs/2); +Ngain_dB = N_dB - 10*log10(N); +Ngain = 10^(Ngain_dB/20); + +% C/No = Carrier Power/noise spectral density +% = power per carrier*number of carriers / noise spectral density +CNo_dB = 10*log10(C) + 10*log10(Nc) - No_dBHz; + +% SNR in equivalent 3000 Hz SSB channel + +B = 3000; +SNR = CNo_dB - 10*log10(B); + +% freq offset simulation states + +phase_offset = 1; +freq_offset = exp(j*2*pi*Foff_hz/Fs); +foff_phase = 1; +t = 0; +foff = 0; +fest_state = 0; +fest_timer = 0; +sync_mem = zeros(1,Nsync_mem); +sync = 0; +sync_log = []; + +snr_log = []; + +Nspec=1024; +spec_mem=zeros(1,Nspec); +SdB = zeros(1,Nspec); + +% --------------------------------------------------------------------- +% Main loop +% --------------------------------------------------------------------- + +for f=1:frames + + % ------------------- + % Modulator + % ------------------- + + tx_bits = get_test_bits(Nc*Nb); + tx_symbols = bits_to_psk(prev_tx_symbols, tx_bits, modulation); + prev_tx_symbols = tx_symbols; + tx_baseband = tx_filter(tx_symbols); + tx_baseband_log = [tx_baseband_log tx_baseband]; + tx_fdm = fdm_upconvert(tx_baseband); + tx_pwr = 0.9*tx_pwr + 0.1*real(tx_fdm)*real(tx_fdm)'/(M); + + % ------------------- + % Channel simulation + % ------------------- + + % frequency offset + + %Foff_hz += 1/Rs; + Foff = Foff_hz; + for i=1:M + % Time varying freq offset + %Foff = Foff_hz + 100*sin(t*2*pi/(300*Fs)); + %t++; + freq_offset = exp(j*2*pi*Foff/Fs); + phase_offset *= freq_offset; + tx_fdm(i) = phase_offset*tx_fdm(i); + end + + tx_fdm = real(tx_fdm); + + % HPA non-linearity + + tx_fdm(find(abs(tx_fdm) > hpa_clip)) = hpa_clip; + tx_fdm_log = [tx_fdm_log tx_fdm]; + + rx_fdm = tx_fdm; + + % AWGN noise + + noise = Ngain*randn(1,M); + noise_pwr = 0.9*noise_pwr + 0.1*noise*noise'/M; + rx_fdm += noise; + rx_fdm_log = [rx_fdm_log rx_fdm]; + + % update spectrum + + l=length(rx_fdm); + spec_mem(1:Nspec-l) = spec_mem(l+1:Nspec); + spec_mem(Nspec-l+1:Nspec) = rx_fdm; + S=fft(spec_mem.*hanning(Nspec)',Nspec); + SdB = 0.9*SdB + 0.1*20*log10(abs(S)); + + + % ------------------- + % Demodulator + % ------------------- + + % shift down to complex baseband + + for i=1:M + fbb_phase_rx = fbb_phase_rx*fbb_rect'; + rx_fdm(i) = rx_fdm(i)*fbb_phase_rx; + end + mag = abs(fbb_phase_rx); + fbb_phase_rx /= mag; + + % frequency offset estimation and correction, need to call rx_est_freq_offset even in sync + % mode to keep states updated + + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M); + [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, M, !sync); + + if sync == 0 + foff = foff_coarse; + end + + foff_log = [ foff_log foff ]; + foff_rect = exp(j*2*pi*foff/Fs); + + for i=1:M + foff_phase *= foff_rect'; + rx_fdm(i) = rx_fdm(i)*foff_phase; + end + + rx_fdm_filter = rxdec_filter(rx_fdm, M); + rx_filt = down_convert_and_rx_filter(rx_fdm_filter, M, M/Q); + + [rx_symbols rx_timing] = rx_est_timing(rx_filt, M); + rx_timing_log = [rx_timing_log rx_timing]; + + %rx_phase = rx_est_phase(rx_symbols); + %rx_phase_log = [rx_phase_log rx_phase]; + %rx_symbols = rx_symbols*exp(j*rx_phase); + + [rx_bits sync_bit foff_fine pd] = psk_to_bits(prev_rx_symbols, rx_symbols, modulation); + if strcmp(modulation,'dqpsk') + rx_symbols_log = [rx_symbols_log pd]; + else + rx_symbols_log = [rx_symbols_log rx_symbols]; + endif + foff -= 0.5*foff_fine; + + prev_rx_symbols = rx_symbols; + sync_bit_log = [sync_bit_log sync_bit]; + + % freq est state machine + + [sync reliable_sync_bit fest_state fest_timer sync_mem] = freq_state(sync_bit, fest_state, fest_timer, sync_mem); + sync_log = [sync_log sync]; + + % Update SNR est + + [sig_est noise_est] = snr_update(sig_est, noise_est, pd); + snr_log = [snr_log calc_snr(sig_est, noise_est)]; + + % count bit errors if we find a test frame + % Allow 15 frames for filter memories to fill and time est to settle + + [test_frame_sync bit_errors] = put_test_bits(test_bits, rx_bits); + + if test_frame_sync == 1 + total_bit_errors = total_bit_errors + bit_errors; + total_bits = total_bits + Ntest_bits; + bit_errors_log = [bit_errors_log bit_errors]; + else + bit_errors_log = [bit_errors_log 0]; + end + + % test frame sync state machine, just for more informative plots + + next_test_frame_sync_state = test_frame_sync_state; + if (test_frame_sync_state == 0) + if (test_frame_sync == 1) + next_test_frame_sync_state = 1; + test_frame_count = 0; + end + end + + if (test_frame_sync_state == 1) + % we only expect another test_frame_sync pulse every 4 symbols + test_frame_count++; + if (test_frame_count == 4) + test_frame_count = 0; + if ((test_frame_sync == 0)) + next_test_frame_sync_state = 0; + end + end + end + test_frame_sync_state = next_test_frame_sync_state; + test_frame_sync_log = [test_frame_sync_log test_frame_sync_state]; +end + +% --------------------------------------------------------------------- +% Print Stats +% --------------------------------------------------------------------- + +ber = total_bit_errors / total_bits; + +% Peak to Average Power Ratio calcs from http://www.dsplog.com + +papr = max(tx_fdm_log.*conj(tx_fdm_log)) / mean(tx_fdm_log.*conj(tx_fdm_log)); +papr_dB = 10*log10(papr); + +% Note Eb/No set point is for Nc data carriers only, excluding pilot. +% This is convenient for testing BER versus Eb/No. Measured SNR & +% Eb/No includes power of pilot. Similar for SNR, first number is SNR +% excluding pilot pwr for Eb/No set point, 2nd value is measured SNR +% which will be a little higher as pilot power is included. Note current SNR +% est algorithm only works for QPSK, gives silly values for 8PSK. + +printf("Bits/symbol.: %d\n", Nb); +printf("Num carriers: %d\n", Nc); +printf("Bit Rate....: %d bits/s\n", Rb); +printf("Eb/No (meas): %2.2f (%2.2f) dB\n", EbNo_dB, 10*log10(0.25*tx_pwr*Fs/(Rs*Nc*noise_pwr))); +printf("bits........: %d\n", total_bits); +printf("errors......: %d\n", total_bit_errors); +printf("BER.........: %1.4f\n", ber); +printf("PAPR........: %1.2f dB\n", papr_dB); +printf("SNR...(meas): %2.2f (%2.2f) dB\n", SNR, calc_snr(sig_est, noise_est)); + +% --------------------------------------------------------------------- +% Plots +% --------------------------------------------------------------------- + +figure(1) +clf; +[n m] = size(rx_symbols_log); +plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+') +axis([-3 3 -3 3]); +title('Scatter Diagram'); + +figure(2) +clf; +subplot(211) +plot(rx_timing_log) +title('timing offset'); +subplot(212) +plot(foff_log, '-;freq offset;') +hold on; +plot(sync_log*75, 'r;Sync State & course(0) fine(1) freq tracking;'); +hold off; +title('Freq offset (Hz)'); + +figure(3) +clf; +subplot(211) +plot(real(tx_fdm_log)); +title('FDM Tx Signal'); +subplot(212) +plot((0:Nspec/2-1)*Fs/Nspec, SdB(1:Nspec/2) - 20*log10(Nspec/2)) +axis([0 Fs/2 -40 0]) +grid +title('FDM Rx Spectrum'); + +figure(4) +clf; +subplot(311) +stem(sync_bit_log) +axis([0 frames 0 1.5]); +title('BPSK Sync') +subplot(312) +stem(bit_errors_log); +title('Bit Errors for test frames') +subplot(313) +plot(test_frame_sync_log); +axis([0 frames 0 1.5]); +title('Test Frame Sync') + +figure(5) +clf +subplot(211) +plot(snr_log) +subplot(212) +%plot(20*log10(sig_est(1:Nc))-20*log10(sig_est(Nc+1))+6) +%axis([1 Nc -6 6]); +sdB_pc = 20*log10(sig_est(1:Nc+1)); +bar(sdB_pc(1:Nc) - mean(sdB_pc(1:Nc))) +axis([0 Nc+1 -3 3]); diff --git a/codec2/branches/0.7/octave/fdmdv_ut_coh.m b/codec2/branches/0.7/octave/fdmdv_ut_coh.m new file mode 100644 index 00000000..a1598878 --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_ut_coh.m @@ -0,0 +1,341 @@ +% fdmdv_ut_coh.m +% + +% Unit Test program for coherent version of FDMDV modem. Used to +% build up the ability to test coherent demodulation of FDMDV +% signals sampled off air. These signals are differentially encoded +% but we can treat the symbols after the diff encoder as PSK symbols. +% +% We keep most of the existing DPSK modem to handle acquisition, frame sync, +% and just the the PSK demo in parallel. The goal here is to measure the BER +% of the test data using coherent PSK, it's not actually a practical modem. + +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +fdmdv; % load modem code + +% Simulation Parameters -------------------------------------- + +frames = 200; +EbNo_dB = 7; +Foff_hz = -100; +hpa_clip = 150; + +% ------------------------------------------------------------ + +tx_filt = zeros(Nc,M); +rx_symbols_log = []; +rx_phase_log = 0; +rx_timing_log = 0; +tx_pwr = 0; +noise_pwr = 0; +rx_fdm_log = []; +rx_baseband_log = []; +rx_bits_offset = zeros(Nc*Nb*2); +prev_tx_symbols = ones(Nc+1,1); +prev_rx_symbols = ones(Nc+1,1); +ferr = 0; +foff = 0; +foff_log = []; +tx_baseband_log = []; +tx_fdm_log = []; + +% BER stats + +total_bit_errors = 0; +total_bits = 0; +bit_errors_log = []; +sync_log = []; +test_frame_sync_log = []; +test_frame_sync_state = 0; + +% SNR estimation states + +sig_est = zeros(Nc+1,1); +noise_est = zeros(Nc+1,1); + +% fixed delay simuation + +Ndelay = M+20; +rx_fdm_delay = zeros(Ndelay,1); + +% --------------------------------------------------------------------- +% Eb/No calculations. We need to work out Eb/No for each FDM carrier. +% Total power is sum of power in all FDM carriers +% --------------------------------------------------------------------- + +C = 1; % power of each FDM carrier (energy/sample). Total Carrier power should = Nc*C = Nc +N = 1; % total noise power (energy/sample) of noise source across entire bandwidth + +% Eb = Carrier power * symbol time / (bits/symbol) +% = C *(1/Rs) / 2 +Eb_dB = 10*log10(C) - 10*log10(Rs) - 10*log10(2); + +No_dBHz = Eb_dB - EbNo_dB; + +% Noise power = Noise spectral density * bandwidth +% Noise power = Noise spectral density * Fs/2 for real signals +N_dB = No_dBHz + 10*log10(Fs/2); +Ngain_dB = N_dB - 10*log10(N); +Ngain = 10^(Ngain_dB/20); + +% C/No = Carrier Power/noise spectral density +% = power per carrier*number of carriers / noise spectral density +CNo_dB = 10*log10(C) + 10*log10(Nc) - No_dBHz; + +% SNR in equivalent 3000 Hz SSB channel + +B = 3000; +SNR = CNo_dB - 10*log10(B); + +% freq offset simulation states + +phase_offset = exp(j*0); +freq_offset = exp(j*2*pi*Foff_hz/Fs); +foff_phase = 1; +t = 0; +foff = 0; +fest_state = 0; +track = 0; +track_log = []; + +snr_log = []; + +rx_symbols_ph_log = []; +prev_rx_symbols_ph = ones(Nc+1,1); +rx_phase_offsets_log = []; +phase_amb_log = []; + +% --------------------------------------------------------------------- +% Main loop +% --------------------------------------------------------------------- + +for f=1:frames + + % ------------------- + % Modulator + % ------------------- + + tx_bits = get_test_bits(Nc*Nb); + tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, 'dqpsk'); + prev_tx_symbols = tx_symbols; + tx_baseband = tx_filter(tx_symbols); + tx_baseband_log = [tx_baseband_log tx_baseband]; + tx_fdm = fdm_upconvert(tx_baseband); + tx_pwr = 0.9*tx_pwr + 0.1*real(tx_fdm)*real(tx_fdm)'/(M); + + % ------------------- + % Channel simulation + % ------------------- + + % frequency offset + + %Foff_hz += 1/Rs; + Foff = Foff_hz; + for i=1:M + % Time varying freq offset + %Foff = Foff_hz + 100*sin(t*2*pi/(300*Fs)); + %t++; + freq_offset = exp(j*2*pi*Foff/Fs); + phase_offset *= freq_offset; + tx_fdm(i) = phase_offset*tx_fdm(i); + end + + tx_fdm = real(tx_fdm); + + % HPA non-linearity + + tx_fdm(find(abs(tx_fdm) > hpa_clip)) = hpa_clip; + tx_fdm_log = [tx_fdm_log tx_fdm]; + + rx_fdm = tx_fdm; + + % AWGN noise + + noise = Ngain*randn(1,M); + noise_pwr = 0.9*noise_pwr + 0.1*noise*noise'/M; + rx_fdm += noise; + rx_fdm_log = [rx_fdm_log rx_fdm]; + + % Delay + + %rx_fdm_delay(1:Ndelay-M) = rx_fdm_delay(M+1:Ndelay); + %rx_fdm_delay(Ndelay-M+1:Ndelay) = rx_fdm; + rx_fdm_delay = rx_fdm; + + % ------------------- + % Demodulator + % ------------------- + + % frequency offset estimation and correction, need to call + % rx_est_freq_offset even in track mode to keep states updated + + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M); + [foff_course S1 S2] = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M); + if track == 0 + foff = foff_course; + end + + %foff = 0; % disable for now + + foff_log = [ foff_log foff ]; + foff_rect = exp(j*2*pi*foff/Fs); + + for i=1:M + foff_phase *= foff_rect'; + rx_fdm_delay(i) = rx_fdm_delay(i)*foff_phase; + end + + % baseband processing + + rx_baseband = fdm_downconvert(rx_fdm_delay(1:M), M); + rx_baseband_log = [rx_baseband_log rx_baseband]; + rx_filt = rx_filter(rx_baseband, M); + + [rx_symbols rx_timing] = rx_est_timing(rx_filt, rx_baseband, M); + rx_symbols_log = [rx_symbols_log rx_symbols.*(conj(prev_rx_symbols)./abs(prev_rx_symbols))*exp(j*pi/4)]; + rx_timing_log = [rx_timing_log rx_timing]; + + % coherent phase offset estimation ------------------------------------ + + [rx_phase_offsets ferr] = rx_est_phase(rx_symbols); + rx_phase_offsets_log = [rx_phase_offsets_log rx_phase_offsets]; + phase_amb_log = [phase_amb_log phase_amb]; + rx_symbols_ph = rx_symbols_mem(:,floor(Nph/2)+1) .* exp(-j*(rx_phase_offsets + phase_amb)); + rx_symbols_ph_log = [rx_symbols_ph_log rx_symbols_ph .* exp(j*pi/4)]; + rx_symbols_ph = -1 + 2*(real(rx_symbols_ph .* exp(j*pi/4)) > 0) + j*(-1 + 2*(imag(rx_symbols_ph .* exp(j*pi/4)) > 0)); + + % Std differential (used for freq offset est and BPSK sync) and psuedo coherent detection ----------------------- + + [rx_bits_unused sync ferr pd] = qpsk_to_bits(prev_rx_symbols, rx_symbols, 'dqpsk'); + [rx_bits sync_unused ferr_unused pd] = qpsk_to_bits(prev_rx_symbols_ph, rx_symbols_ph, 'dqpsk'); + + %---------------------------------------------------------------------- + + foff -= 0.5*ferr; + prev_rx_symbols = rx_symbols; + prev_rx_symbols_ph = rx_symbols_ph; + sync_log = [sync_log sync]; + + % freq est state machine + + [track fest_state] = freq_state(sync, fest_state); + track_log = [track_log track]; + + % Update SNR est + + [sig_est noise_est] = snr_update(sig_est, noise_est, pd); + snr_log = [snr_log calc_snr(sig_est, noise_est)]; + + % count bit errors if we find a test frame + + [test_frame_sync bit_errors] = put_test_bits(test_bits, rx_bits); + + if (test_frame_sync == 1) && (f > 15) + total_bit_errors = total_bit_errors + bit_errors; + total_bits = total_bits + Ntest_bits; + bit_errors_log = [bit_errors_log bit_errors]; + else + bit_errors_log = [bit_errors_log 0]; + end + + % test frame sync state machine, just for more informative plots + + next_test_frame_sync_state = test_frame_sync_state; + if (test_frame_sync_state == 0) + if (test_frame_sync == 1) + next_test_frame_sync_state = 1; + test_frame_count = 0; + end + end + + if (test_frame_sync_state == 1) + % we only expect another test_frame_sync pulse every 4 symbols + test_frame_count++; + if (test_frame_count == 4) + test_frame_count = 0; + if ((test_frame_sync == 0)) + next_test_frame_sync_state = 0; + end + end + end + test_frame_sync_state = next_test_frame_sync_state; + test_frame_sync_log = [test_frame_sync_log test_frame_sync_state]; +end + +% --------------------------------------------------------------------- +% Print Stats +% --------------------------------------------------------------------- + +ber = total_bit_errors / total_bits; + +% Note Eb/No set point is for Nc data carriers only, excluding pilot. +% This is convenient for testing BER versus Eb/No. Measured Eb/No +% includes power of pilot. Similar for SNR, first number is SNR excluding +% pilot pwr for Eb/No set point, 2nd value is measured SNR which will be a little +% higher as pilot power is included. + +printf("\n"); +printf("Eb/No (meas): %2.2f (%2.2f) dB\n", EbNo_dB, 10*log10(0.25*tx_pwr*Fs/(Rs*Nc*noise_pwr))); +printf("SNR...(meas): %2.2f (%2.2f) dB\n", SNR, calc_snr(sig_est, noise_est)); +printf("\nDPSK\n"); +printf(" bits......: %d\n", total_bits); +printf(" errors....: %d\n", total_bit_errors); +printf(" BER.......: %1.4f\n", ber); + +% --------------------------------------------------------------------- +% Plots +% --------------------------------------------------------------------- + +figure(1) +clf; +[n m] = size(rx_symbols_log); +plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+') +%plot(real(rx_symbols_log(2,15:m)),imag(rx_symbols_log(2,15:m)),'+') +axis([-3 3 -3 3]); +title('Scatter Diagram'); + +figure(2) +clf; +subplot(211) +plot(rx_timing_log) +title('timing offset (samples)'); +subplot(212) +plot(foff_log, '-;freq offset;') +hold on; +plot(track_log*75, 'r;course-fine;'); +hold off; +title('Freq offset (Hz)'); + +figure(3) +clf; +subplot(311) +stem(sync_log) +axis([0 frames 0 1.5]); +title('BPSK Sync') +subplot(312) +stem(bit_errors_log); +title('Bit Errors for test frames') +subplot(313) +plot(test_frame_sync_log); +axis([0 frames 0 1.5]); +title('Test Frame Sync') + +figure(4) +clf; +[n m] = size(rx_symbols_ph_log); +plot(real(rx_symbols_ph_log(1:Nc+1,15:m)),imag(rx_symbols_ph_log(1:Nc+1,15:m)),'+') +%plot(real(rx_symbols_ph_log(2,15:m)),imag(rx_symbols_ph_log(2,15:m)),'+') +axis([-3 3 -3 3]); +title('Scatter Diagram - after phase correction'); + +figure(5) +clf; +subplot(211) +plot(rx_phase_offsets_log(1,:)) +subplot(212) +plot(phase_amb_log(1,:)) +title('Rx Phase Offset Est') diff --git a/codec2/branches/0.7/octave/fdmdv_ut_freq_off.m b/codec2/branches/0.7/octave/fdmdv_ut_freq_off.m new file mode 100644 index 00000000..395bcc5b --- /dev/null +++ b/codec2/branches/0.7/octave/fdmdv_ut_freq_off.m @@ -0,0 +1,489 @@ +% fdmdv_ut_freq_off.m +% David Rowe 17 June 2014 +% +% Unit Test program for freq offset estimation in FDMDV modem. +% +% Copyright David Rowe 2012 This program is +% distributed under the terms of the GNU General Public License +% Version 2 + +% [ ] sweep of different delays +% [ ] sweep of Eb/No +% [ ] sweep of freq offsets +% [ ] step change in foff +% + time to respond +% [ ] plot/print pass fail/relevant stats +% + variance +% + histogram of freq ests? + +fdmdv; % load modem code +hf_sim; % load hf sim code + +% --------------------------------------------------------------------- +% Eb/No calculations. We need to work out Eb/No for each FDM carrier. +% Total power is sum of power in all FDM carriers. These calcs set the +% Eb/No of the data carriers, Eb/No of pilot will be higher. +% --------------------------------------------------------------------- + +function [Nsd SNR] = calc_Nsd_from_EbNo(EbNo_dB) + global Rs; + global Nb; + global Nc; + global Fs; + + C = 1; % power of each FDM carrier (energy/sample). Total Carrier power should = Nc*C = Nc + N = 1; % total noise power (energy/sample) of noise source across entire bandwidth + + % Eb = Carrier power * symbol time / (bits/symbol) + % = C *(1/Rs) / Nb + Eb_dB = 10*log10(C) - 10*log10(Rs) - 10*log10(Nb); + + No_dBHz = Eb_dB - EbNo_dB; + + % Noise power = Noise spectral density * bandwidth + % Noise power = Noise spectral density * Fs/2 for real signals + N_dB = No_dBHz + 10*log10(Fs/2); + Ngain_dB = N_dB - 10*log10(N); + Nsd = 10^(Ngain_dB/20); + + % C/No = Carrier Power/noise spectral density + % = power per carrier*number of carriers / noise spectral density + CNo_dB = 10*log10(C) + 10*log10(Nc) - No_dBHz; + + % SNR in equivalent 3000 Hz SSB channel, adding extra power for pilot to get + % true SNR. + + B = 3000; + SNR = CNo_dB - 10*log10(B) + 10*log10((Nc+4)/Nc); +end + +% we keep a m sample buffer in sample_memory +% update sample_memory with n samples each time this function is called +% outputs one nfft2 slice of spectrogram in dB. Good idea to make nfft2 a power of 2 + +function [S, states_out] = spectrogram_update(samples, n, states_in) + sample_memory = states_in.sample_memory; + m = states_in.m; + nfft2 = states_in.nfft2; + lower_clip_dB = states_in.lower_clip_dB; + dec = states_in.dec; + + sample_memory(1:m-n) = sample_memory(n+1:m); + sample_memory(m-n+1:m) = samples; + + F = fft(sample_memory .* hanning(m)', 2*nfft2); + S = 20*log10(abs(F(1:dec:nfft2))/(nfft2)); + S(find(S < lower_clip_dB)) = lower_clip_dB; % clip lower limit + + states_out = states_in; + states_out.sample_memory = sample_memory; +end + +% ------------------------------------------------------------ + +function sim_out = freq_off_est_test(sim_in) + global Nc; + global Nb; + global M; + global Fs; + global pilot_lut_index; + global prev_pilot_lut_index; + global pilot_lpf1; + global Npilotlpf; + global spread; + global spread_2ms; + global hf_gain; + + EbNovec = sim_in.EbNovec; + Ndelay = sim_in.delay; + frames = sim_in.frames; + startup_delay = sim_in.startup_delay; + allowable_error = sim_in.allowable_error; + foff_hz = sim_in.foff_hz; + hf_sim = sim_in.hf_sim; + hf_delay = floor(sim_in.hf_delay_ms*Fs/1000); + plot_type = sim_in.plot_type; + + % work out gain for HF model + % e = sum((g*s)^2) = g*g*sum(s^2) = N, g = sqrt(N/sum(s^2)) + % compute so e=N + + s1 = spread(1:frames*M); + s2 = [zeros(hf_delay,1); spread_2ms(1:frames*M)]; + s2 = s2(1:frames*M); + + p = (s1+s2)'*(s1+s2); + hf_gain = sqrt(frames*M/p); + p2 = (hf_gain*(s1+s2))'*(hf_gain*(s1+s2)); + + if hf_sim + channel_model = "HF"; + else + channel_model = "AWGN"; + end + + % spectrogram states + + spec_states.m = 8*M; + spec_states.nfft2 = 2 ^ ceil(log2(spec_states.m/2)); + spec_states.dec = 4; + spec_states.sample_memory = zeros(1, spec_states.m); + spec_states.lower_clip_dB = -30; + + printf("\n%s\n", sim_in.test_name); + printf(" Channel EbNo SNR(calc) SNR(meas) SD(Hz) Hits Hits(%%) Result\n"); + + % --------------------------------------------------------------------- + % Main loop + % --------------------------------------------------------------------- + + for ne = 1:length(EbNovec) + EbNo_dB = EbNovec(ne); + [Nsd SNR] = calc_Nsd_from_EbNo(EbNo_dB); + hits = 0; + + tx_filt = zeros(Nc,M); + prev_tx_symbols = ones(Nc+1,1); + + tx_fdm_log = []; + rx_fdm_log = []; + pilot_lpf1_log = []; + S1_log = []; + rx_fdm_delay = zeros(M+Ndelay,1); + + % freq offset simulation states + + phase_offset = 1; + Nmedian = 20; + foff_median=zeros(1,Nmedian); + + % hf sim states + + path2 = zeros(1,hf_delay+M); + sum_sig = 0; + sum_noise = 0; + + % state machine + state = 0; + fest_current = 0; + fdelta = 5; + candidate_thresh = 10; + foff_est_thresh_prev = 0; + + for f=1:frames + + % ------------------- Modulator ------------------- + + tx_bits = get_test_bits(Nc*Nb); + tx_symbols = bits_to_psk(prev_tx_symbols, tx_bits, 'dqpsk'); + + % simulate BPF filtering of +/- 200 Hz + % tx_symbols(1:6) = 0; tx_symbols(9:Nc) = 0; + + prev_tx_symbols = tx_symbols; + tx_baseband = tx_filter(tx_symbols); + tx_fdm = fdm_upconvert(tx_baseband); + tx_fdm_log = [tx_fdm_log real(tx_fdm)]; + + % ------------------- Channel simulation ------------------- + + % frequency offset + + for i=1:M + freq_offset = exp(j*2*pi*foff_hz(f)/Fs); + phase_offset *= freq_offset; + tx_fdm(i) = phase_offset*tx_fdm(i); + end + + % optional HF channel sim + + if hf_sim + path1 = tx_fdm .* conj(spread(f*M+1:f*M+M)'); + + path2(1:hf_delay) = path2(M+1:hf_delay+M); + path2(hf_delay+1:hf_delay+M) = tx_fdm .* conj(spread_2ms(f*M+1:f*M+M)'); + + tx_fdm = hf_gain*(path1 + path2(1:M)); + end + sum_sig += tx_fdm * tx_fdm'; + + rx_fdm = real(tx_fdm); + + % AWGN noise + + noise = Nsd*randn(1,M); + sum_noise += noise * noise'; + rx_fdm += noise; + rx_fdm_log = [rx_fdm_log rx_fdm]; + + % Fixed Delay + + rx_fdm_delay(1:Ndelay) = rx_fdm_delay(M+1:M+Ndelay); + rx_fdm_delay(Ndelay+1:M+Ndelay) = rx_fdm; + + % ------------------- Freq Offset Est ------------------- + + % frequency offset estimation and correction, need to call + % rx_est_freq_offset even in track mode to keep states updated + + [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = ... + get_pilot(pilot_lut_index, prev_pilot_lut_index, M); + [foff_est S1 S2] = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M); + pilot_lpf1_log = [pilot_lpf1_log pilot_lpf1(Npilotlpf-M+1:Npilotlpf)]; + S1_log(f,:) = fftshift(S1); + S2_log(f,:) = fftshift(S2); + + % raw estimate + + foff_log(ne,f) = foff_est; + maxS1_log(ne,f) = max(S1.*conj(S1)/(S1*S1')); + maxS2_log(ne,f) = max(S2.*conj(S2)/(S2*S2')); + + % median filter post-processed + + foff_median(1:Nmedian-1) = foff_median(2:Nmedian); + foff_median(Nmedian) = foff_est; + foff_median_log(ne,f) = foff_coarse = median(foff_median); + + % state machine post-processed + + next_state = state; + if state == 0 + if abs(foff_est - fest_current) > fdelta + fest_candidate = foff_est; + candidate_count = 0; + next_state = 1; + end + end + if state == 1 + if abs(foff_est - fest_candidate) > fdelta + next_state = 0; + end + candidate_count++; + if candidate_count > candidate_thresh + fest_current = fest_candidate; + next_state = 0; + end + end + state = next_state; + foff_statemach_log(ne,f) = fest_current; + + % threshold post processed + + if (maxS1_log(ne,f) > 0.06) || (maxS2_log(ne,f) > 0.06) + %if (maxS1_log(ne,f) > 0.08) + foff_thresh_log(ne,f) = foff_est; + else + foff_thresh_log(ne,f) = foff_est_thresh_prev; + end + foff_est_thresh_prev = foff_thresh_log(ne,f); + + % hit/miss stats + fest_current = foff_statemach_log(ne,f); + if (f > startup_delay) && (abs(fest_current - foff_hz(f)) < allowable_error) + hits++; + end + + if length(EbNovec) == 1 + [spectrogram(f,:) spec_states] = spectrogram_update(rx_fdm, M, spec_states); + end + end + + % results for this EbNo value + + sim_out.foff_sd(ne) = std(foff_log(ne,startup_delay:frames)); + sim_out.hits = hits; + sim_out.hits_percent = 100*sim_out.hits/(frames-startup_delay); + sim_out.SNRvec(ne) = SNR; + sim_out.tx_fdm_log = tx_fdm_log; + sim_out.rx_fdm_log = rx_fdm_log; + + % noise we have measures is 4000 Hz wide, we want noise in 3000 Hz BW + + snr_meas = 10*log10(sum_sig/(sum_noise*4000/3000)); + + printf(" %6s %5.2f % -5.2f % -5.2f %3.2f %d %3.2f ", ... + channel_model, EbNo_dB, SNR, snr_meas, sim_out.foff_sd(ne), sim_out.hits, sim_out.hits_percent); + + if sim_out.hits_percent == 100 + printf("PASS\n"); + else + printf("FAIL\n"); + figure(5) + clf + plot(abs(foff_statemach_log(ne,:) - foff_hz < allowable_error)); + end + + % plots if single dimension vector + + if length(EbNovec) == 1 + fmin = -200; fmax = 200; + figure(1) + clf; + subplot(411) + plot(foff_log(ne,:)) + axis([1 frames fmin fmax]); + ylabel("Foff raw") + subplot(412) + plot(foff_median_log(ne,:)) + axis([1 frames fmin fmax]); + ylabel("Foff median") + subplot(413) + plot(foff_statemach_log(ne,:),'g') + ylabel("Foff state") + axis([1 frames fmin fmax]); + subplot(414) + plot(foff_thresh_log(ne,:)) + ylabel("Foff thresh") + axis([1 frames fmin fmax]); + xlabel("Frames") + grid; + + figure(2) + clf; + plot(maxS1_log(ne,:)); + axis([1 frames 0 0.2]); + xlabel("Frames") + ylabel("max(abs(S1/S2))") + grid; + hold on; + plot(maxS2_log(ne,:),'g'); + hold off; + + figure(3) + [n m] = size(S1_log); + if strcmp(plot_type,"mesh") + mesh(-200+400*(0:m-1)/256,1:n,abs(S1_log(:,:))); + xlabel('Freq (Hz)'); ylabel('Frame num'); zlabel("max(abs(S1))") + else + imagesc(1:n,-200+400*(0:(m-1))/m,abs(S1_log(:,:))'); + set(gca,'YDir','normal') + ylabel('Freq (Hz)'); xlabel('Frame num'); + axis([1 n -200 200]) + end + + figure(4) + clf + [n m] = size(spectrogram); + if strcmp(plot_type,"mesh") + mesh((4000/m)*(1:m),1:n,spectrogram); + xlabel('Freq (Hz)'); ylabel('Frame num'); zlabel('Amplitude (dB)'); + else + imagesc(1:n,(4000/m)*(1:m),spectrogram') + set(gca,'YDir','normal') + ylabel('Freq (Hz)'); xlabel('Frame num'); + axis([1 n 500 2500]) + end + + sim_out.spec = spectrogram; + sim_out.tx_fdm_log = spectrogram; + end + end +end + +% --------------------------------------------------------------------- +% Run Automated Tests +% --------------------------------------------------------------------- + +more off; + +function test1 + global M; + global Rs; + + sim_in.test_name = "Test 1: range of Eb/No (SNRs) in AWGN channel"; + sim_in.EbNovec = [3:10 99]; + sim_in.delay = M/2; + sim_in.frames = Rs*3; + sim_in.foff_hz(1:sim_in.frames) = 50; + sim_in.startup_delay = 0.5*Rs; + sim_in.allowable_error = 5; + sim_in.hf_sim = 0; + sim_in.hf_delay_ms = 2; + sim_in.delay = M/2; + sim_in.plot_type = "waterfall"; + + sim_out = freq_off_est_test(sim_in); + + figure(5) + clf + subplot(211) + plot(sim_in.EbNovec, sim_out.foff_sd) + hold on; + plot(sim_in.EbNovec, sim_out.foff_sd,'+') + hold off; + xlabel("Eb/No (dB)") + ylabel("Std Dev (Hz)") + axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]); + + subplot(212) + plot(sim_out.SNRvec,sim_out.foff_sd) + hold on; + plot(sim_out.SNRvec,sim_out.foff_sd,'+') + hold off; + xlabel("SNR (dB)") + ylabel("Std Dev (Hz)") + axis([(min(sim_out.SNRvec)-1) (max(sim_out.SNRvec)+1) -1 10]); +end + + +function test2 + sim_in.test_name = "Test 2: range of Eb/No (SNRs) in HF multipath channel" + sim_in.EbNovec = 0:10; + sim_in.delay = 2; + sim_in.hf_sim = 1; + sim_in.hf_delay_ms = 2; + sim_in.frames = Rs*2; + sim_in.foff_hz = 0; + sim_in.startup_delay = Rs/2; + sim_in.allowable_error = 5; + + sim_out = freq_off_est_test(sim_in); + + figure(5) + clf + subplot(211) + plot(sim_in.EbNovec,sim_out.foff_sd) + hold on; + plot(sim_in.EbNovec,sim_out.foff_sd,'+') + hold off; + xlabel("Eb/No (dB)") + ylabel("Std Dev") + axis([(min(sim_in.EbNovec)-1) (max(sim_in.EbNovec)+1) -1 10]); +end + +function test3 + global M; + global Rs; + + sim_in.test_name = "Test 3: 30 Seconds in HF multipath channel at 0dB-ish SNR"; + sim_in.EbNovec = 13; + sim_in.hf_sim = 0; + sim_in.hf_delay_ms = 2; + sim_in.delay = M/2; + sim_in.frames = Rs; + sim_in.foff_hz(1:sim_in.frames) = -50; + sim_in.startup_delay = Rs; % allow 1 second in heavily faded channels + sim_in.allowable_error = 5; + sim_in.plot_type = "mesh"; + sim_out = freq_off_est_test(sim_in); +endfunction + +function animated_gif + figure(4) + for i=5:5:360 + view(i,45) + filename=sprintf('fdmdv_fig%05d.png',i); + print(filename); + end + if 0 + for i=90:-5:-270 + view(45,i) + filename=sprintf('fdmdv_fig%05d.png',i); + print(filename); + end + end +endfunction + +test3; + diff --git a/codec2/branches/0.7/octave/fm.m b/codec2/branches/0.7/octave/fm.m new file mode 100644 index 00000000..0c9e349a --- /dev/null +++ b/codec2/branches/0.7/octave/fm.m @@ -0,0 +1,469 @@ +% fm.m +% David Rowe Dec 2014 +% +% Analog FM Octave simulation functions. + +1; + +graphics_toolkit ("gnuplot"); + +function fm_states = analog_fm_init(fm_states) + + % FM modulator constants + + Fs = fm_states.Fs; FsOn2 = Fs/2; + fm_max = fm_states.fm_max; % max modulation freq + fd = fm_states.fd; % (max) deviation + fm_states.m = fd/fm_max; % modulation index + fm_states.Bfm = Bfm = 2*(fd+fm_max); % Carson's rule for FM signal bandwidth + fm_states.tc = tc = 50E-6; + fm_states.prede = [1 -(1 - 1/(tc*Fs))]; % pre/de emp filter coeffs + fm_states.ph_dont_limit = 0; % Limit rx delta-phase + + % Select length of filter to be an integer number of symbols to + % assist with "fine" timing offset estimation. Set Ts to 1 for + % analog modulation. + + Ts = fm_states.Ts; + desired_ncoeffs = 200; + ncoeffs = floor(desired_ncoeffs/Ts+1)*Ts; + + % "coarse" timing offset is half filter length, we have two filters. + % This is the delay the two filters introduce, so we need to adjust + % for this when comparing tx to trx bits for BER calcs. + + fm_states.nsym_delay = ncoeffs/Ts; + + % input filter gets rid of excess noise before demodulator, as too much + % noise causes atan2() to jump around, e.g. -pi to pi. However this + % filter can cause harmonic distortion at very high SNRs, as it knocks out + % some of the FM signal spectra. This filter isn't really required for high + % SNRs > 20dB. + + fc = (Bfm/2)/(FsOn2); + fm_states.bin = firls(ncoeffs,[0 fc*(1-0.05) fc*(1+0.05) 1],[1 1 0.01 0.01]); + + % demoduator output filter to limit us to fm_max (e.g. 3kHz) + + fc = fm_max/(FsOn2); + fm_states.bout = firls(ncoeffs,[0 0.95*fc 1.05*fc 1], [1 1 0.01 0.01]); +endfunction + + +function fm_fir_coeff_file(fm_states, filename) + global gt_alpha5_root; + global Nfilter; + + f=fopen(filename,"wt"); + + fprintf(f,"/* Generated by fm_fir_coeff_file() Octave function in fm.m */\n\n"); + fprintf(f,"const float bin[]={\n"); + for m=1:length(fm_states.bin)-1 + fprintf(f," %g,\n", fm_states.bin(m)); + endfor + fprintf(f," %g\n};\n\n", fm_states.bin(length(fm_states.bin))); + + fprintf(f,"const float bout[]={\n"); + for m=1:length(fm_states.bout)-1 + fprintf(f," %g,\n", fm_states.bout(m)); + endfor + fprintf(f," %g\n};\n", fm_states.bout(length(fm_states.bout))); + + fclose(f); +endfunction + + +function tx = analog_fm_mod(fm_states, mod) + Fs = fm_states.Fs; + fc = fm_states.fc; wc = 2*pi*fc/Fs; + fd = fm_states.fd; wd = 2*pi*fd/Fs; + nsam = length(mod); + + if fm_states.pre_emp + mod = filter(fm_states.prede,1,mod); + mod = mod/max(mod); % AGC to set deviation + end + + tx_phase = 0; + tx = zeros(1,nsam); + + for i=0:nsam-1 + w = wc + wd*mod(i+1); + tx_phase = tx_phase + w; + tx_phase = tx_phase - floor(tx_phase/(2*pi))*2*pi; + tx(i+1) = exp(j*tx_phase); + end +endfunction + + +function [rx_out rx_bb] = analog_fm_demod(fm_states, rx) + Fs = fm_states.Fs; + fc = fm_states.fc; wc = 2*pi*fc/Fs; + fd = fm_states.fd; wd = 2*pi*fd/Fs; + nsam = length(rx); + t = 0:(nsam-1); + + rx_bb = rx .* exp(-j*wc*t); % down to complex baseband + rx_bb = filter(fm_states.bin,1,rx_bb); + + % differentiate first, in rect domain, then find angle, this puts + % signal on the positive side of the real axis + + rx_bb_diff = [ 1 rx_bb(2:nsam) .* conj(rx_bb(1:nsam-1))]; + rx_out = atan2(imag(rx_bb_diff),real(rx_bb_diff)); + + % limit maximum phase jumps, to remove static type noise at low SNRs + if !fm_states.ph_dont_limit + rx_out(find(rx_out > wd)) = wd; + rx_out(find(rx_out < -wd)) = -wd; + end + rx_out *= (1/wd); + + if fm_states.output_filter + rx_out = filter(fm_states.bout,1,rx_out); + end + if fm_states.de_emp + rx_out = filter(1,fm_states.prede,rx_out); + end +endfunction + + +function sim_out = analog_fm_test(sim_in) + nsam = sim_in.nsam; + CNdB = sim_in.CNdB; + verbose = sim_in.verbose; + + Fs = fm_states.Fs = 96000; + fm_max = fm_states.fm_max = 3E3; + fd = fm_states.fd = 5E3; + fm_states.fc = 24E3; + + fm_states.pre_emp = pre_emp = sim_in.pre_emp; + fm_states.de_emp = de_emp = sim_in.de_emp; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + sim_out.Bfm = fm_states.Bfm; + + Bfm = fm_states.Bfm; + m = fm_states.m; tc = fm_states.tc; + t = 0:(nsam-1); + + fm = 1000; wm = 2*pi*fm/fm_states.Fs; + + % start simulation + + for ne = 1:length(CNdB) + + % work out the variance we need to obtain our C/N in the bandwidth + % of the FM demod. The gaussian generator randn() generates noise + % with a bandwidth of Fs + + aCNdB = CNdB(ne); + CN = 10^(aCNdB/10); + variance = Fs/(CN*Bfm); + + % FM Modulator ------------------------------- + + mod = sin(wm*t); + tx = analog_fm_mod(fm_states, mod); + + % Channel --------------------------------- + + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx + noise; + + % FM Demodulator + + [rx_out rx_bb] = analog_fm_demod(fm_states, rx); + + % notch out test tone + + w = 2*pi*fm/Fs; beta = 0.99; + rx_notch = filter([1 -2*cos(w) 1],[1 -2*beta*cos(w) beta*beta], rx_out); + + % measure power with and without test tone to determine S+N and N + + settle = 1000; % filter settling time, to avoid transients + nsettle = nsam - settle; + + sinad = (rx_out(settle:nsam) * rx_out(settle:nsam)')/nsettle; + nad = (rx_notch(settle:nsam) * rx_notch(settle:nsam)')/nsettle; + + snr = (sinad-nad)/nad; + sim_out.snrdB(ne) = 10*log10(snr); + + % Theory from FMTutorial.pdf, Lawrence Der, Silicon labs paper + + snr_theory_dB = aCNdB + 10*log10(3*m*m*(m+1)); + fx = 1/(2*pi*tc); W = fm_max; + I = (W/fx)^3/(3*((W/fx) - atan(W/fx))); + I_dB = 10*log10(I); + + sim_out.snr_theorydB(ne) = snr_theory_dB; + sim_out.snr_theory_pre_dedB(ne) = snr_theory_dB + I_dB; + + if verbose > 1 + printf("modn index: %2.1f Bfm: %.0f Hz\n", m, Bfm); + end + + if verbose > 0 + printf("C/N: %4.1f SNR: %4.1f dB THEORY: %4.1f dB or with pre/de: %4.1f dB\n", + aCNdB, 10*log10(snr), snr_theory_dB, snr_theory_dB+I_dB); + end + + if verbose > 1 + figure(1) + subplot(211) + plot(20*log10(abs(fft(rx)))) + title('FM Modulator Output Spectrum'); + axis([1 length(tx) 0 100]); + subplot(212) + Rx_bb = 20*log10(abs(fft(rx_bb))); + plot(Rx_bb) + axis([1 length(tx) 0 100]); + title('FM Demodulator (baseband) Input Spectrum'); + + figure(2) + subplot(211) + plot(rx_out(settle:nsam)) + axis([1 4000 -1 1]) + subplot(212) + Rx = 20*log10(abs(fft(rx_out(settle:nsam)))); + plot(Rx(1:10000)) + axis([1 10000 0 100]); + end + + end + +endfunction + + +function run_fm_curves + sim_in.nsam = 96000; + sim_in.verbose = 1; + sim_in.pre_emp = 0; + sim_in.de_emp = 0; + sim_in.CNdB = -4:2:20; + + sim_out = analog_fm_test(sim_in); + + figure(1) + clf + plot(sim_in.CNdB, sim_out.snrdB,"r;FM Simulated;"); + hold on; + plot(sim_in.CNdB, sim_out.snr_theorydB,"g;FM Theory;"); + plot(sim_in.CNdB, sim_in.CNdB,"b; SSB Theory;"); + hold off; + grid("minor"); + xlabel("FM demod input C/N (dB)"); + ylabel("FM demod output S/N (dB)"); + legend("boxoff"); + + % C/No curves + + Bfm_dB = 10*log10(sim_out.Bfm); + Bssb_dB = 10*log10(3000); + + figure(2) + clf + plot(sim_in.CNdB + Bfm_dB, sim_out.snrdB,"r;FM Simulated;"); + hold on; + plot(sim_in.CNdB + Bfm_dB, sim_out.snr_theorydB,"g;FM Theory;"); + plot(sim_in.CNdB + Bssb_dB, sim_in.CNdB,"b; SSB Theory;"); + hold off; + grid("minor"); + xlabel("FM demod input C/No (dB)"); + ylabel("FM demod output S/N (dB)"); + legend("boxoff"); + +endfunction + + +function run_fm_single + sim_in.nsam = 96000; + sim_in.verbose = 2; + sim_in.pre_emp = 0; + sim_in.de_emp = 0; + + sim_in.CNdB = 20; + sim_out = analog_fm_test(sim_in); +end + + +function fm_mod_file(file_name_out) + fm_states.Fs = 48000; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.fc = fm_states.Fs/4; + fm_states.pre_emp = 0; + fm_states.de_emp = 0; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + + nsam = fm_states.Fs * 10; + t = 0:(nsam-1); + fm = 1000; wm = 2*pi*fm/fm_states.Fs; + mod = sin(wm*t); + tx = analog_fm_mod(fm_states, mod); + + tx_out = tx*16384; + fout = fopen(file_name_out,"wb"); + fwrite(fout, tx_out, "short"); + fclose(fout); +endfunction + + +function fm_demod_file(file_name_out, file_name_in) + fin = fopen(file_name_in,"rb"); + rx = fread(fin,"short")'; + rx = rx(100000:length(rx)); % strip of wave header + fclose(fin); + + Fs = fm_states.Fs = 48000; + fm_max = fm_states.fm_max = 3E3; + fd = fm_states.fd = 5E3; + fm_states.fc = 12E3; + + fm_states.pre_emp = 0; + fm_states.de_emp = 1; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + + [rx_out rx_bb] = analog_fm_demod(fm_states, rx); + + rx_out *= 20000; + fout = fopen(file_name_out,"wb"); + fwrite(fout, rx_out, "short"); + fclose(fout); + + figure(1) + subplot(211) + plot(rx) + subplot(212) + plot(20*log10(abs(fft(rx)))) + title('FM Dmodulator Intput Spectrum'); + + figure(2) + subplot(211) + Rx_bb = 20*log10(abs(fft(rx_bb))); + plot(Rx_bb) + title('FM Demodulator (baseband) Input Spectrum'); + + subplot(212) + plot(20*log10(abs(fft(rx_out)))) + title('FM Dmodulator Output Spectrum'); + + figure(3) + plot(rx_out) + title('FM Dmodulator Output'); + + % estimate SNR, C/No etc + + npower_window = 1024; + rx_power = conv(rx.^2,ones(1,npower_window))/(npower_window); + rx_power_dB = 10*log10(rx_power); + figure; + subplot(211) + plot(rx); + subplot(212) + plot(rx_power_dB); + axis([1 length(rx_power) max(rx_power_dB)-9 max(rx_power_dB)+1]) + grid("minor") + + % estimate FM demod output SNR if a 1000 Hz tone is present + + w = 2*pi*1000/Fs; beta = 0.99; + rx_notch = filter([1 -2*cos(w) 1],[1 -2*beta*cos(w) beta*beta], rx_out); + + rx_out_power = conv(rx_out.^2,ones(1,npower_window))/(npower_window); + rx_out_power_dB = 10*log10(rx_out_power); + rx_notch_power = conv(rx_notch.^2,ones(1,npower_window))/(npower_window); + rx_notch_power_dB = 10*log10(rx_notch_power); + figure; + plot(rx_out_power_dB,'r;FM demod output power;'); + hold on; + plot(rx_notch_power_dB,'b;1000 Hz notch filter output power;'); + plot(rx_out_power_dB-rx_notch_power_dB,'g;1000 Hz tone SNR;'); + hold off; + legend("boxoff"); + ylabel('dB'); + xlabel('Time (samples)'); + grid("minor") + +endfunction + + +% generate filter coeffs for C implementation of FM demod + +function make_coeff_file + fm_states.Fs = 44400; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.fc = fm_states.Fs/4; + + fm_states.pre_emp = 0; + fm_states.de_emp = 0; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + + fm_fir_coeff_file(fm_states, "fm_fir_coeff.h") +endfunction + +function test_fm_modulator + fm_states.Fs = 48000; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + %fm_states.fc = fm_states.Fs/4; + fm_states.fc = 0; + + fm_states.pre_emp = 0; + fm_states.de_emp = 0; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + + test_t = [1:(fm_states.Fs*10)]; + test_freq1 = 2*pi*3000/fm_states.Fs; + test_freq2 = 2*pi*1000/fm_states.Fs; + + test_sig = .5*sin(test_t*test_freq1) + .5*sin(test_t*test_freq2); + %test_sig = zeros(1,length(test_t)); + %test_sig = ones(1,length(test_t)); + + ftsig = fopen("fm_test_sig.raw","wb"); + fwrite(ftsig,test_sig*16384,"short"); + fclose(ftsig); + + system("../fm_test fm_test_sig.raw fm_test_out.raw"); + ftmod = fopen("fm_test_out.raw","r"); + test_mod_p = rot90(fread(ftmod,"short"))/16384; + test_mod_r = test_mod_p(1:2:length(test_mod_p)); + test_mod_i = test_mod_p(2:2:length(test_mod_p)); + test_mod = test_mod_r .+ i*test_mod_i; + fclose(ftmod); + + comp_mod = analog_fm_mod(fm_states,test_sig); + + figure(1) + comp_mod_real = real(comp_mod); + size(comp_mod_real) + size(test_mod) + mod_diff = zeros(1,length(test_mod)); + mod_diff = test_mod .- comp_mod; + plot(test_t,real(test_mod .- comp_mod),test_t,imag(test_mod .- comp_mod)); + +endfunction + +more off; + +%run_fm_curves +%fm_demod_file("ssb_fm_out.raw","~/Desktop/ssb_fm.wav") +%fm_demod_file("ssb25_fm_de.raw", "~/Desktop/ssb25db.wav") +%run_fm_single +%make_coeff_file +%fm_mod_file("fm_1000.raw"); +%test_fm_modulator diff --git a/codec2/branches/0.7/octave/fm_radio_filt_model.txt b/codec2/branches/0.7/octave/fm_radio_filt_model.txt new file mode 100644 index 00000000..368f7e2a --- /dev/null +++ b/codec2/branches/0.7/octave/fm_radio_filt_model.txt @@ -0,0 +1,8 @@ +# Created by Octave 4.0.0, Wed Feb 10 20:14:16 2016 CST +# name: filt +# type: matrix +# rows: 1 +# columns: 1001 + 4.111934884608988e-05 4.529266752036107e-05 5.012294778018435e-05 5.387673663540811e-05 5.656595617636202e-05 5.754247327156636e-05 5.745029328387444e-05 5.810382275274602e-05 6.038440324493526e-05 6.151519405194188e-05 5.995001465356246e-05 5.965124091807071e-05 5.894036887788694e-05 5.282714911187688e-05 4.16286613756742e-05 2.733281113424976e-05 1.151301392357209e-05 -5.011952829637155e-06 -2.038060526743049e-05 -2.88950898384027e-05 -3.140205230802841e-05 -2.680377848432233e-05 -1.425766597021347e-05 2.754137907668088e-06 2.533067638032289e-05 5.098405707491412e-05 7.524935743597888e-05 9.490108720790089e-05 0.0001114408649087926 0.0001232907290105822 0.0001298558067129026 0.0001314146843973354 0.000126874153326206 0.0001211256678148737 0.0001128586850331393 0.0001021842594143064 9.340521285980458e-05 8.465588232787989e-05 7.602754602719386e-05 7.476083494605245e-05 7.795597606716329e-05 8.085052742218461e-05 8.855370570715267e-05 9.993747197784049e-05 0.0001100627878797455 0.0001157727179778551 0.0001211159686312227 0.0001276193402990368 0.0001274951568358215 0.0001237937282219144 0.0001199864757482567 0.0001145773485240607 0.0001078643622955885 9.949247921871633e-05 9.282321723585223e-05 8.670764514445847e-05 8.236867203976522e-05 8.178131856442866e-05 8.653490906422325e-05 9.474089964535933e-05 0.0001046664881685255 0.0001171407871684955 0.0001284375906324497 0.0001435371988464706 0.0001538019728144609 0.000157821986861445 0.0001617032194688335 0.000161139381508245 0.0001573044997290387 0.0001505912434581831 0.0001444545226667355 0.0001371895926370354 0.0001282916901414378 0.0001164777490003531 0.0001017868860228118 8.38857960955751e-05 6.397168698635467e-05 4.505424718694719e-05 2.609404178225459e-05 9.390120446350423e-06 -6.139147851498066e-06 -1.74535589572342e-05 -2.432568386408825e-05 -2.719609151945925e-05 -2.559556014458576e-05 -1.629614429158625e-05 -1.3631941893713e-06 1.383091083546116e-05 3.467670361993851e-05 6.180780852724694e-05 8.838658249276322e-05 0.0001119097915371812 0.0001372537482217498 0.0001573246833069575 0.0001685794934648446 0.0001736521706833196 0.0001743894362264053 0.000170440134727034 0.0001570034141396783 0.0001415291461137907 0.0001293030383250257 0.0001170129681552746 0.0001056747747162765 9.587608125739278e-05 8.209630166614193e-05 6.930393501059805e-05 6.085367944553192e-05 5.275816447026444e-05 4.194241650880381e-05 3.420239452264183e-05 3.304591574725996e-05 3.024288241806293e-05 3.012154305643325e-05 3.738917134601837e-05 4.770388200482866e-05 5.781977436721907e-05 7.420695272211161e-05 8.723833080263831e-05 9.505250826889752e-05 0.0001065158066456628 0.0001104312822684124 0.0001098275912662366 0.000107206024810334 0.0001025516069602837 9.894340278646091e-05 9.407503918864603e-05 8.7319365554045e-05 8.141197975598374e-05 8.422482885728253e-05 9.626406072217444e-05 0.0001047837385634293 0.0001197702730190546 0.0001441800101209614 0.000160456934552367 0.0001774138786603596 0.0001926926553236415 0.0001984206468214209 0.0001945597427125206 0.0001836754090288533 0.0001644147124457892 0.0001450923278130216 0.000131637876080013 0.0001194268883117051 0.0001142849115928036 0.0001090067194513346 0.0001167532618894625 0.0001293962113881341 0.0001304604164937581 0.0001310955784948294 0.0001353721674033472 0.0001341681487126995 0.0001198264422032539 0.0001012747411089002 7.153140827090248e-05 4.191084339680094e-05 2.303431628630918e-05 1.138159045954137e-05 1.214910078795732e-05 2.029103100753587e-05 3.914274819454478e-05 7.436668389413293e-05 0.0001131985409445768 0.0001541458098186209 0.0001981874567952984 0.0002293068332902554 0.0002574810386944711 0.0002797524248574673 0.000280098997160137 0.0002691199306180641 0.0002483396512410882 0.0002130987320308693 0.0001696438030090705 0.0001233684249499195 8.43926061428125e-05 5.198681974621152e-05 3.567320177887548e-05 4.949705291163776e-05 7.787515033943651e-05 0.0001300149878038 0.0002020713027294515 0.0002783857988869775 0.0003565185832637648 0.0004241895316775589 0.000479626912439881 0.0005159892932585141 0.0005326203262494115 0.0005366426137323655 0.0005240387399286967 0.0005041051313799223 0.0004864550530904512 0.0004727638664349475 0.0004645950604270155 0.0004548102499574072 0.000455527247961606 0.0004612992161328969 0.0004674556394527062 0.0004716258022734013 0.0004668087315020519 0.0004622641649603435 0.0004465585690774155 0.000425258701401412 0.00039751658715728 0.0003635800988525798 0.0003328960310700836 0.0003048849901663823 0.0002810007495450609 0.0002673721567286335 0.0002702604512501591 0.0002862572870604029 0.0003084406671027542 0.0003355248671444351 0.0003761847353904122 0.0004148377173810094 0.0004485558688712593 0.0004800892227209435 0.0005013700140284393 0.0005138034260364562 0.000523675449512398 0.0005317635475002124 0.0005322207128124348 0.0005292033760978139 0.0005269773541343302 0.0005175977188382754 0.0004993895797658196 0.0004858979454010794 0.0004684001252653537 0.0004587034220581103 0.0004638037190751786 0.0004761823498486873 0.0004885372867673723 0.0005043751480265481 0.0005446800229664075 0.0005890158012063288 0.0006231865628459465 0.0006616542116343469 0.0006972231165628774 0.0007040149509799145 0.000712178888077443 0.0007101214361108593 0.0006931453291674526 0.0006924927262763824 0.0006853703272953059 0.0007004172297637321 0.0007466476213180197 0.00080183074513318 0.0008653125079193471 0.000932413333045206 0.0009780458869915588 0.001000137248327646 0.0009991649016365171 0.0009565650123854935 0.0008785166874477056 0.0007712153995398795 0.0006440612144425213 0.0005014886072902373 0.0003647207877911045 0.0002314452035966864 0.0001215619643926978 5.102070582077005e-05 3.53881850929961e-06 5.024961716295417e-06 4.952203678213442e-05 0.0001260092656341149 0.0002274300947131321 0.0003513571295408856 0.0004918678731923972 0.0006212972022330388 0.0007279470267812717 0.0008134213275591345 0.000856084224659261 0.0008367582390177951 0.0007963231371937705 0.0007308920792511363 0.0006278320617335954 0.0005155411192978977 0.0004049366284488046 0.0003146483534597321 0.000232809201512697 0.0001611481391302676 0.0001276356087955276 0.0001258477694353633 0.000148410784426943 0.0001791264427517458 0.0002152831436118296 0.0002722059220446592 0.0003148588847685937 0.0003235563379009122 0.0003234961169067191 0.0003141523386480817 0.0002970986813756301 0.0002753731712067278 0.0002391073092942144 0.0002217724458095815 0.0002500563490184254 0.0002860821491880679 0.0003319979542964821 0.0004127132318400748 0.0005101781526047186 0.0006116301200159012 0.0007154307983328388 0.0008127224793692451 0.0008838704404048489 0.0009291650300966136 0.0009480193252716987 0.0009397344198433433 0.0009095689814133252 0.0008547924134192681 0.0007841007737282723 0.0007018037456432335 0.0006005948006725787 0.0005078784471340359 0.0004406418213749735 0.0003714124757418396 0.0003264057688551507 0.0003047322000871897 0.0002906911596356952 0.0002861738822980829 0.0002743316277907311 0.0002636405310368626 0.0002526665586205466 0.000226716276058895 0.0001875320324724495 0.0001636750239487869 0.0001372388125105794 0.0001222573562860838 0.0001269254248804013 0.0001139495649892648 0.0001106414381361491 0.0001196292706110303 0.0001189746129582091 0.0001112327955701268 0.0001296685790607515 0.0001643819608291414 0.0001878863422254414 0.0002344588678557017 0.0003203860709214426 0.0004064572654023451 0.0004940737860301076 0.000596014360602431 0.0006749848938371238 0.0007389096824511 0.0007792584703839535 0.0007965798134060041 0.0008056540909816971 0.0007849711152884964 0.000736062831596933 0.0006709962921592219 0.000603317655045247 0.0005383093164802969 0.0004900142937176716 0.0004551531490340078 0.000449534106387221 0.0004708650906301616 0.0004934795110626268 0.0005345974954791178 0.0006078660984573032 0.000702762715896311 0.0007775394691744047 0.0008818221619807017 0.001000679407785467 0.001092707546060794 0.001210613677564552 0.001312089019158298 0.001405270807169912 0.001490114661507714 0.001531394363834887 0.001555410794560944 0.001543704930528568 0.001470479573974331 0.001389350245308104 0.00128125012918577 0.001130987351527693 0.001007863016474597 0.0008564828937716682 0.0007074501288004987 0.0006213523466697201 0.0005713540643662852 0.0005583807693821872 0.0006196820100433617 0.0007361817663542591 0.0008554464717298295 0.0009758354537658702 0.001030406744297961 0.001035680319931336 0.001012121155964727 0.0009548313236383478 0.0008790095856581987 0.0008222269458738788 0.0007806888647762658 0.00070288663268893 0.0006454619358970265 0.0006054134743706602 0.000585536509799107 0.0005761856239940797 0.0005868746914752406 0.0006209602772533917 0.0006504193524742758 0.0006871616100603014 0.0007025287393104163 0.0007171995117985032 0.0007172937860848917 0.0006961439382863224 0.0006718024855287201 0.0006254758975065462 0.0005416137326971845 0.0004555547815183704 0.0003867779579310328 0.0003290178707355808 0.0002953031361596086 0.000255119760230264 0.0002488539502124204 0.0002677640501578254 0.0002652005008809371 0.0002906090024497945 0.0003166398471483209 0.0003089920401697223 0.0003114866028324989 0.0003133184110010134 0.0002840418132516435 0.0002386702280686958 0.0001892280180500572 0.0001115506030916713 1.983929251944428e-07 -0.0001282921891725907 -0.0002827272707108253 -0.0004368740799478221 -0.0005848618113809967 -0.0007194441046966012 -0.0008196524633909468 -0.0009048202133206396 -0.0009695404302984057 -0.00101680303425177 -0.00104331484535875 -0.001044670960196941 -0.001096308220052877 -0.001198928001528127 -0.001307622162194671 -0.001475710104821832 -0.001686034525628763 -0.001932017480014 -0.002224364121912755 -0.002509340882950428 -0.002795659773184621 -0.00309134921771924 -0.003339621248074061 -0.003527096039668997 -0.003713374797631359 -0.003865457109591278 -0.003984544055673171 -0.004135912398823348 -0.004315826807472575 -0.004496951439455919 -0.004688515788482826 -0.004898735004401356 -0.005110796780538788 -0.005339127441411028 -0.00553035210769078 -0.005705695069882694 -0.005870819376498557 -0.006004875496650137 -0.006110777442311181 -0.006164210930893388 -0.00618756905448379 -0.006096936349455484 -0.005939592020122337 -0.005693193052915928 -0.005354094079859258 -0.005027974684133828 -0.004692376525298168 -0.004435709093992968 -0.004274376328604747 -0.004208157300760209 -0.004223103959974963 -0.004327093561393999 -0.004497183833286816 -0.004613763151773346 -0.004718655531703288 -0.00476162995946275 -0.004733215833039038 -0.004717818557505252 -0.004685430263054647 -0.004754957289104762 -0.004977412914427918 -0.005345713165123564 -0.005956911360135976 -0.006682313612074329 -0.007507498625754038 -0.008207774465767762 -0.008390747806307929 -0.007774338884105022 -0.005813672313667084 -0.002020675163340676 0.003934699513891164 0.01218867179800687 0.0227189593674642 0.03474656425430857 0.0474559430852135 0.05969919927081149 0.06940044807963783 0.07690251527634465 0.08229165974889782 0.07690251527634465 0.06940044807963783 0.05969919927081149 0.04745594308521349 0.03474656425430857 0.02271895936746419 0.01218867179800687 0.003934699513891165 -0.002020675163340676 -0.005813672313667083 -0.007774338884105022 -0.008390747806307929 -0.008207774465767762 -0.007507498625754038 -0.006682313612074331 -0.005956911360135976 -0.005345713165123564 -0.004977412914427918 -0.004754957289104762 -0.004685430263054647 -0.004717818557505251 -0.004733215833039039 -0.00476162995946275 -0.004718655531703288 -0.004613763151773345 -0.004497183833286817 -0.004327093561393998 -0.004223103959974966 -0.004208157300760209 -0.004274376328604745 -0.00443570909399297 -0.004692376525298168 -0.005027974684133829 -0.00535409407985926 -0.005693193052915932 -0.005939592020122337 -0.006096936349455483 -0.006187569054483791 -0.006164210930893387 -0.006110777442311182 -0.006004875496650137 -0.005870819376498557 -0.005705695069882694 -0.00553035210769078 -0.005339127441411028 -0.005110796780538787 -0.004898735004401356 -0.004688515788482826 -0.004496951439455919 -0.004315826807472577 -0.004135912398823348 -0.003984544055673172 -0.003865457109591278 -0.00371337479763136 -0.003527096039668997 -0.003339621248074061 -0.00309134921771924 -0.00279565977318462 -0.002509340882950424 -0.002224364121912757 -0.001932017480014 -0.001686034525628767 -0.001475710104821831 -0.001307622162194672 -0.001198928001528127 -0.001096308220052873 -0.001044670960196942 -0.00104331484535875 -0.001016803034251772 -0.0009695404302984054 -0.00090482021332064 -0.0008196524633909476 -0.0007194441046966014 -0.0005848618113809963 -0.000436874079947822 -0.0002827272707108247 -0.0001282921891725906 1.9839292519393e-07 0.0001115506030916713 0.0001892280180500569 0.0002386702280686963 0.0002840418132516444 0.0003133184110010132 0.0003114866028324986 0.0003089920401697223 0.0003166398471483207 0.0002906090024497948 0.0002652005008809363 0.000267764050157825 0.0002488539502124205 0.0002551197602302644 0.000295303136159608 0.0003290178707355802 0.0003867779579310346 0.0004555547815183697 0.0005416137326971845 0.000625475897506546 0.0006718024855287199 0.0006961439382863226 0.0007172937860848909 0.0007171995117985036 0.0007025287393104162 0.0006871616100603015 0.000650419352474276 0.0006209602772533919 0.0005868746914752408 0.0005761856239940797 0.0005855365097991073 0.0006054134743706607 0.0006454619358970264 0.0007028866326889299 0.0007806888647762659 0.000822226945873879 0.0008790095856581987 0.0009548313236383482 0.001012121155964728 0.001035680319931336 0.001030406744297961 0.0009758354537658703 0.0008554464717298296 0.0007361817663542591 0.0006196820100433625 0.0005583807693821864 0.000571354064366285 0.0006213523466697193 0.0007074501288005006 0.0008564828937716656 0.001007863016474597 0.001130987351527696 0.001281250129185769 0.001389350245308103 0.001470479573974332 0.001543704930528569 0.001555410794560944 0.001531394363834887 0.001490114661507714 0.001405270807169912 0.001312089019158298 0.001210613677564552 0.001092707546060794 0.001000679407785467 0.0008818221619807018 0.0007775394691744045 0.0007027627158963109 0.0006078660984573031 0.000534597495479118 0.0004934795110626265 0.0004708650906301616 0.0004495341063872209 0.0004551531490340077 0.0004900142937176715 0.0005383093164802969 0.000603317655045247 0.0006709962921592213 0.0007360628315969327 0.0007849711152884964 0.0008056540909816968 0.0007965798134060039 0.000779258470383954 0.0007389096824511003 0.0006749848938371232 0.0005960143606024314 0.00049407378603011 0.0004064572654023451 0.000320386070921443 0.0002344588678557023 0.0001878863422254417 0.0001643819608291412 0.0001296685790607518 0.0001112327955701267 0.0001189746129582092 0.0001196292706110302 0.0001106414381361493 0.000113949564989265 0.0001269254248804011 0.000122257356286084 0.0001372388125105794 0.0001636750239487874 0.0001875320324724492 0.0002267162760588951 0.0002526665586205469 0.0002636405310368628 0.000274331627790731 0.0002861738822980834 0.0002906911596356955 0.0003047322000871902 0.0003264057688551512 0.0003714124757418389 0.0004406418213749726 0.0005078784471340354 0.000600594800672577 0.0007018037456432339 0.0007841007737282728 0.0008547924134192688 0.0009095689814133239 0.0009397344198433432 0.0009480193252716988 0.0009291650300966141 0.0008838704404048497 0.0008127224793692449 0.0007154307983328389 0.0006116301200159011 0.0005101781526047185 0.0004127132318400751 0.0003319979542964823 0.0002860821491880682 0.0002500563490184256 0.0002217724458095814 0.0002391073092942146 0.0002753731712067281 0.0002970986813756304 0.0003141523386480819 0.0003234961169067191 0.0003235563379009124 0.0003148588847685941 0.0002722059220446591 0.0002152831436118294 0.0001791264427517463 0.0001484107844269434 0.0001258477694353638 0.0001276356087955284 0.0001611481391302664 0.0002328092015126938 0.0003146483534597321 0.0004049366284488059 0.000515541119297898 0.0006278320617335942 0.0007308920792511362 0.0007963231371937704 0.0008367582390177949 0.000856084224659261 0.0008134213275591343 0.0007279470267812722 0.0006212972022330388 0.0004918678731923973 0.0003513571295408855 0.0002274300947131321 0.000126009265634115 4.952203678213429e-05 5.024961716295127e-06 3.538818509299518e-06 5.102070582076996e-05 0.0001215619643926977 0.0002314452035966865 0.0003647207877911044 0.0005014886072902379 0.0006440612144425216 0.0007712153995398789 0.0008785166874477058 0.0009565650123854939 0.0009991649016365179 0.001000137248327646 0.0009780458869915582 0.0009324133330452072 0.0008653125079193493 0.0008018307451331798 0.000746647621318018 0.0007004172297637317 0.0006853703272953076 0.0006924927262763831 0.0006931453291674521 0.0007101214361108594 0.0007121788880774427 0.000704014950979915 0.0006972231165628779 0.000661654211634347 0.0006231865628459464 0.0005890158012063288 0.0005446800229664074 0.0005043751480265481 0.0004885372867673724 0.0004761823498486873 0.0004638037190751788 0.0004587034220581102 0.0004684001252653539 0.0004858979454010797 0.0004993895797658201 0.0005175977188382752 0.0005269773541343305 0.0005292033760978143 0.0005322207128124349 0.0005317635475002128 0.000523675449512398 0.000513803426036456 0.0005013700140284385 0.0004800892227209432 0.0004485558688712597 0.0004148377173810098 0.0003761847353904126 0.0003355248671444355 0.0003084406671027549 0.0002862572870604022 0.000270260451250159 0.0002673721567286339 0.0002810007495450609 0.000304884990166382 0.0003328960310700833 0.00036358009885258 0.0003975165871572802 0.000425258701401412 0.0004465585690774157 0.0004622641649603433 0.0004668087315020517 0.0004716258022734012 0.0004674556394527063 0.0004612992161328973 0.0004555272479616062 0.000454810249957407 0.0004645950604270157 0.0004727638664349478 0.000486455053090451 0.0005041051313799224 0.0005240387399286972 0.0005366426137323651 0.0005326203262494113 0.0005159892932585147 0.0004796269124398812 0.0004241895316775592 0.0003565185832637645 0.0002783857988869775 0.0002020713027294521 0.0001300149878038001 7.787515033943645e-05 4.94970529116387e-05 3.567320177887565e-05 5.198681974621122e-05 8.439260614281255e-05 0.0001233684249499196 0.0001696438030090706 0.0002130987320308694 0.0002483396512410884 0.000269119930618064 0.0002800989971601369 0.0002797524248574673 0.0002574810386944714 0.0002293068332902553 0.0001981874567952985 0.0001541458098186209 0.0001131985409445768 7.436668389413293e-05 3.914274819454482e-05 2.02910310075359e-05 1.214910078795737e-05 1.138159045954142e-05 2.303431628630914e-05 4.191084339680085e-05 7.153140827090229e-05 0.0001012747411089004 0.0001198264422032543 0.0001341681487126989 0.0001353721674033473 0.0001310955784948295 0.0001304604164937583 0.0001293962113881343 0.0001167532618894624 0.0001090067194513343 0.0001142849115928038 0.0001194268883117053 0.0001316378760800131 0.0001450923278130218 0.0001644147124457893 0.0001836754090288532 0.0001945597427125205 0.000198420646821421 0.0001926926553236415 0.0001774138786603597 0.0001604569345523672 0.0001441800101209615 0.0001197702730190544 0.0001047837385634294 9.626406072217448e-05 8.422482885728265e-05 8.141197975598381e-05 8.7319365554045e-05 9.4075039188646e-05 9.894340278646086e-05 0.0001025516069602838 0.0001072060248103339 0.0001098275912662369 0.0001104312822684126 0.000106515806645663 9.505250826889828e-05 8.723833080263867e-05 7.420695272211161e-05 5.781977436721884e-05 4.770388200482809e-05 3.7389171346018e-05 3.012154305643296e-05 3.024288241806269e-05 3.30459157472601e-05 3.42023945226418e-05 4.194241650880383e-05 5.275816447026444e-05 6.085367944553199e-05 6.930393501059805e-05 8.209630166614197e-05 9.587608125739296e-05 0.0001056747747162764 0.0001170129681552745 0.0001293030383250257 0.0001415291461137908 0.0001570034141396783 0.0001704401347270341 0.0001743894362264053 0.0001736521706833197 0.0001685794934648447 0.0001573246833069577 0.00013725374822175 0.0001119097915371812 8.838658249276298e-05 6.180780852724682e-05 3.467670361993845e-05 1.383091083546099e-05 -1.363194189371131e-06 -1.629614429158657e-05 -2.559556014458577e-05 -2.719609151945906e-05 -2.432568386408844e-05 -1.745355895723421e-05 -6.139147851498011e-06 9.390120446350515e-06 2.609404178225465e-05 4.505424718694725e-05 6.397168698635465e-05 8.388579609557507e-05 0.0001017868860228118 0.0001164777490003533 0.0001282916901414377 0.0001371895926370353 0.0001444545226667357 0.0001505912434581831 0.0001573044997290388 0.0001611393815082451 0.0001617032194688336 0.0001578219868614449 0.000153801972814461 0.0001435371988464706 0.0001284375906324499 0.0001171407871684956 0.0001046664881685255 9.474089964535937e-05 8.653490906422336e-05 8.178131856442878e-05 8.236867203976517e-05 8.670764514445867e-05 9.282321723585233e-05 9.949247921871623e-05 0.0001078643622955885 0.0001145773485240607 0.0001199864757482572 0.0001237937282219144 0.0001274951568358209 0.0001276193402990368 0.0001211159686312227 0.0001157727179778552 0.0001100627878797457 9.993747197784049e-05 8.855370570715271e-05 8.085052742218457e-05 7.795597606716331e-05 7.47608349460523e-05 7.602754602719387e-05 8.465588232787989e-05 9.340521285980456e-05 0.0001021842594143064 0.0001128586850331394 0.0001211256678148737 0.0001268741533262061 0.0001314146843973354 0.0001298558067129026 0.0001232907290105823 0.0001114408649087925 9.490108720790098e-05 7.524935743597891e-05 5.098405707491407e-05 2.533067638032283e-05 2.754137907668097e-06 -1.425766597021359e-05 -2.680377848432208e-05 -3.140205230802843e-05 -2.889508983840295e-05 -2.038060526743043e-05 -5.011952829637147e-06 1.151301392357218e-05 2.733281113424968e-05 4.16286613756742e-05 5.28271491118769e-05 5.894036887788697e-05 5.965124091807064e-05 5.995001465356243e-05 6.151519405194192e-05 6.038440324493523e-05 5.810382275274606e-05 5.745029328387439e-05 5.754247327156637e-05 5.656595617636194e-05 5.387673663540817e-05 5.012294778018432e-05 4.529266752036116e-05 4.11193488460899e-05 + + diff --git a/codec2/branches/0.7/octave/fmfsk.m b/codec2/branches/0.7/octave/fmfsk.m new file mode 100644 index 00000000..4b3cc910 --- /dev/null +++ b/codec2/branches/0.7/octave/fmfsk.m @@ -0,0 +1,346 @@ +% +% fmfsk.m +% Author: Brady O'Brien 3 Feb 2016 +% Copyright 2016 David Rowe +% +% All rights reserved. +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License veRbion 2, as +% published by the Free Software Foundation. This program is +% distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +% License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with this program; if not, see . + +% mancyfsk.m modem, extracted and made suitable for C implementation + +fm; +pkg load signal; +pkg load parallel; +1; + +% Init fmfsk modem +%Fs is sample frequency +%Rb is pre-manchester bit rate +function states = fmfsk_init(Fs,Rb) + assert(mod(Fs,Rb*2)==0); + + %Current fixed processing buffer size, in non-ME bits + nbit = 96; + + states.Rb = Rb; + states.Rs = Rb*2; % Manchester-encoded bitrate + states.Fs = Fs; + states.Ts = Fs/states.Rs; + states.N = nbit*2*states.Ts; + states.nin = states.N; % Samples in the next demod cycle + states.nstash = states.Ts*2; % How many samples to stash away between proc cycles for timing adjust + states.nmem = states.N+(4*states.Ts); + states.nsym = nbit*2; + states.nbit = nbit; + + %tates.nsym = floor(states.Rs*.080); + %states.nbit = floor(states.Rb*.080) + %Old sample memory + + states.oldsamps = zeros(1,states.nmem); + + %Last sampled-stream output, for odd bitstream generation + states.lastint = 0; + + %Some stats + states.norm_rx_timing = 0; + +endfunction + +%Generate a stream of manchester-coded bits to be sent +% to any ordinary FM modulator or VCO or something +function tx = fmfsk_mod(states,inbits) + Ts = states.Ts; + tx = zeros(1,length(inbits)*2); + for ii = 1:length(inbits) + st = 1 + (ii-1)*Ts*2; + md = st+Ts-1; + en = md+Ts; + if inbits(ii)==0 + tx(st:md) = -ones(1,Ts); + tx(md+1:en) = ones(1,Ts); + else + tx(st:md) = ones(1,Ts); + tx(md+1:en) = -ones(1,Ts); + end + end +endfunction + +%Demodulate a bag of bits from the output of an FM demodulator +% This function produces nbits output bits and takes states.nin samples +function [rx_bits states] = fmfsk_demod(states,rx) + Ts = states.Ts; + Fs = states.Fs; + Rs = states.Rs; + nin = states.nin; + N = states.N; + nsym = states.nsym; + nbits = states.nsym/2; + nmem = states.nmem; + nstash = states.nstash; + + nold = nmem-nin; + ssamps = states.oldsamps; + + + %Shift in nin samples + ssamps(1:nold) = ssamps(nmem-nold+1:nmem); + ssamps(nold+1:nmem) = rx; + states.oldsamps = ssamps; + + rx_filt = zeros(1,(nsym+1)*Ts); + %Integrate Ts input samples at every offset + %This is the same thing as filtering with a filter of all ones + % out to Ts. + % It's implemented like this for ease of C-porting + for ii=(1:(nsym+1)*Ts) + st = ii; + en = st+Ts-1; + rx_filt(ii) = sum(ssamps(st:en)); + end + states.rx_filt = rx_filt; + % Fine timing estimation ------------------------------------------------------ + + % Estimate fine timing using line at Rs/2 that Manchester encoding provides + % We need this to sync up to Manchester codewords. + Np = length(rx_filt); + w = 2*pi*(Rs)/Fs; + x = (rx_filt .^ 2) * exp(-j*w*(0:Np-1))'; + norm_rx_timing = angle(x)/(2*pi)-.42; + + rx_timing = round(norm_rx_timing*Ts); + + %If rx timing is too far out, ask for more or less sample the next time + % around to even it all out + next_nin = N; + if norm_rx_timing > -.2; + next_nin += Ts/2; + end + if norm_rx_timing < -.65; + next_nin -= Ts/2; + end + + states.nin = next_nin; + states.norm_rx_timing = norm_rx_timing; + %'Even' and 'Odd' manchester bitstream. + % We'll figure out which to produce later + rx_even = zeros(1,nbits); + rx_odd = zeros(1,nbits); + apeven = 0; + apodd = 0; + + sample_offset = (Ts/2)+Ts+rx_timing-1; + + symsamp = zeros(1,nsym); + + % Figure out the bits of the 'even' and 'odd' ME streams + % Also sample rx_filt offset by what fine timing determined along the way + % Note: ii is a zero-indexed array pointer, for less mind-breaking c portage + lastv = states.lastint; + for ii = (0:nsym-1) + currv = rx_filt(sample_offset+(ii*Ts)+1); + mdiff = lastv-currv; + lastv = currv; + mbit = mdiff>0; + symsamp(ii+1) = currv; + if mod(ii,2)==1 + apeven += abs(mdiff); + rx_even( floor(ii/2)+1 ) = mbit; + else + apodd += abs(mdiff); + rx_odd( floor(ii/2)+1 ) = mbit; + end + end + states.symsamp = symsamp; + % Decide on the correct ME alignment + if(apeven>apodd) + rx_bits = rx_even; + else + rx_bits = rx_odd; + end + + states.lastint = lastv; +endfunction + +% run_sim copypasted from fsk_horus.m +% simulation of tx and rx side, add noise, channel impairments ---------------------- + +function fmfsk_run_sim(EbNodB,timing_offset=0,de=0,of=0,hpf=0) + test_frame_mode = 2; + frames = 70; + %EbNodB = 3; + %timing_offset = 0.0; % see resample() for clock offset below + %fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + df = 0; % tx tone freq drift in Hz/s + dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',1); + randn('state',1); + + Fs = 48000; + Rbit = 2400; + + % ---------------------------------------------------------------------- + + fm_states.pre_emp = 0; + fm_states.de_emp = de; + fm_states.Ts = Fs/(Rbit*2); + fm_states.Fs = Fs; + fm_states.fc = Fs/4; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.output_filter = of; + fm_states = analog_fm_init(fm_states); + + % ---------------------------------------------------------------------- + + states = fmfsk_init(Fs,Rbit); + + states.verbose = 0x1; + Rs = states.Rs; + nsym = states.nsym; + Fs = states.Fs; + nbit = states.nbit; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rb*EbNo); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nbit)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nbit*(frames+1))); + end + if test_frame_mode == 3 + % repeating sequence of all symbols + % great for initial test of demod if nothing else works, + % look for this pattern in rx_bits + + % ...10101... + tx_bits = zeros(1, states.nbit*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + + end + + load fm_radio_filt_model.txt + + [b, a] = cheby1(4, 1, 300/Fs, 'high'); % 300Hz HPF to simulate FM radios + + tx_pmod = fmfsk_mod(states, tx_bits); + tx = analog_fm_mod(fm_states, tx_pmod); + + tx = tx(10:length(tx)); + + if(timing_offset>0) + tx = resample(tx, 1000,1001); % simulated 1000ppm sample clock offset + end + + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise'; + + %Demod by analog fm + rx = analog_fm_demod(fm_states, rx); + + %High-pass filter to simulate the FM radios + if hpf>0 + printf("high-pass filtering!\n") + rx = filter(b,a,rx); + end + rx = filter(filt,1,rx); + + figure(4) + title("Spectrum of rx-ed signal after FM demod and FM radio channel"); + plot(20*log10(abs(fft(rx)))) + figure(5) + title("Time domain of rx-ed signal after FM demod and FM radio channel"); + plot(rx) + %rx = real(rx); + %b1 = fir2(100, [0 4000 5200 48000]/48000, [1 1 0.5 0.5]); + %rx = filter(b1,1,rx); + %[b a] = cheby2(6,40,[3000 6000]/(Fs/2)); + %rx = filter(b,a,rx); + %rx = sign(rx); + %rx(find (rx > 1)) = 1; + %rx(find (rx < -1)) = -1; + + % dump simulated rx file + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,2*nbit); + x_log = []; + timing_nl_log = []; + norm_rx_timing_log = []; + f_int_resample_log = []; + f_log = []; + EbNodB_log = []; + rx_bits_log = []; + rx_bits_sd_log = []; + + for f=1:frames + + % extract nin samples from input stream + + nin = states.nin; + en = st + states.nin - 1; + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + [rx_bits states] = fmfsk_demod(states, sf); + + rx_bits_buf(1:nbit) = rx_bits_buf(nbit+1:2*nbit); + rx_bits_buf(nbit+1:2*nbit) = rx_bits; + rx_bits_log = [rx_bits_log rx_bits]; + + end + + ber = 1; + ox = 1; + rx_bits = rx_bits_log; + bitcnt = length(tx_bits); + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + figure(3); + plot(xor(rx_bits(ox:length(rx_bits)),tx_bits(1:length(rx_bits)+1-ox))) + + printf("BER: %f Errors: %d Bits:%d\n",ber,best_nerr,bitcnt-offset); + + endfunction + + +% demodulate a file of 8kHz 16bit short samples -------------------------------- + + + + diff --git a/codec2/branches/0.7/octave/fsk.m b/codec2/branches/0.7/octave/fsk.m new file mode 100644 index 00000000..d91ba303 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk.m @@ -0,0 +1,251 @@ +% fsk.m +% David Rowe Nov 2014 + +% Simulation to test FSK demod +% +% TODO +% [X] Code up mod/non-coh demod/AWGN channel simulation +% [X] Eb/No verses BER curves +% [X] test analog FM with pre/de-emphahsis +% + this will introduce delay, use fir filter, group delay +% [X] channel simulation of HT/FM radio +% + filtering, varying modulation index +% [ ] GMSK +% [X] refactor to plot analog FM demod curves +% [X] SSB curves +% [-] different modn index beta curves, +% + not really important for now +% [ ] plot to illustrate harmonic dist, +% [X] integration with AFSK, AFSK-FM, v AFSK-SSB (ie FSK) +% [-] fine timing offset for pre/de filters? +% + do we need interpolation as well? +% + might leave this as pre/de not significant now +% [X] C/No curves? +% [X] spectrum plots or analog FM and FSK +% [ ] figures + +rand('state',1); +randn('state',1); +graphics_toolkit ("gnuplot"); + +fm; + +function sim_out = fsk_ber_test(sim_in) + Fs = 96000; + fmark = sim_in.fmark; + fspace = sim_in.fspace; + Rs = sim_in.Rs; + Ts = Fs/Rs; + emphasis = 50E-6; + verbose = sim_in.verbose; + + nsym = sim_in.nsym; + nsam = nsym*Ts; + EbNodB = sim_in.EbNodB; + + fm = sim_in.fm; + + if fm + fm_states.pre_emp = 0; + fm_states.de_emp = 0; + fm_states.Ts = Ts; + fm_states.Fs = Fs; + fm_states.fc = Fs/4; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + end + + % simulate over a range of Eb/No values + + for ne = 1:length(EbNodB) + Nerrs = Terrs = Tbits = 0; + + % randn() generates noise spread across the entire Fs bandwidth. + % The power (aka variance) of this noise is N = NoFs, or No = + % N/Fs. The power of each bit is C=1, so the energy of each bit + % is Eb=1/Rs. We want to find N as a function of Eb/No, so: + + % Eb/No = (1/Rs)/(N/Fs) = Fs/(RsN) + % N = Fs/(Rs(Eb/No)) + + aEbNodB = EbNodB(ne); + EbNo = 10^(aEbNodB/10); + variance = Fs/(Rs*EbNo); + + % Modulator ------------------------------- + + tx_bits = round(rand(1, nsym)); + tx = zeros(1,nsam); + tx_phase = 0; + + for i=1:nsym + for k=1:Ts + if tx_bits(i) == 1 + tx_phase += 2*pi*fmark/Fs; + else + tx_phase += 2*pi*fspace/Fs; + end + tx_phase = tx_phase - floor(tx_phase/(2*pi))*2*pi; + tx((i-1)*Ts+k) = exp(j*tx_phase); + end + end + + % Optional AFSK over FM modulator + + if sim_in.fm + % FM mod takes real input; +/- 1 for correct deviation + tx = analog_fm_mod(fm_states, real(tx)); + end + + % Channel --------------------------------- + + % We use complex (single sided) channel simulation, as it's convenient + % for the FM simulation. + + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx + noise; + if verbose > 1 + printf("EbNo: %f Eb: %f var No: %f EbNo (meas): %f\n", + EbNo, var(tx)*Ts/Fs, var(noise)/Fs, (var(tx)*Ts/Fs)/(var(noise)/Fs)); + end + save fsk tx_bits rx + + % Optional AFSK over FM demodulator + + if sim_in.fm + % scaling factor for convenience to match pure FSK + rx_bb = 2*analog_fm_demod(fm_states, rx); + else + rx_bb = rx; + end + + % Demodulator ----------------------------- + + % non-coherent FSK demod + + mark_dc = rx_bb .* exp(-j*(0:nsam-1)*2*pi*fmark/Fs); + space_dc = rx_bb .* exp(-j*(0:nsam-1)*2*pi*fspace/Fs); + + rx_bits = zeros(1, nsym); + for i=1:nsym + st = (i-1)*Ts+1; + en = st+Ts-1; + mark_int(i) = sum(mark_dc(st:en)); + space_int(i) = sum(space_dc(st:en)); + rx_bits(i) = abs(mark_int(i)) > abs(space_int(i)); + end + + if fm + d = fm_states.nsym_delay; + error_positions = xor(rx_bits(1+d:nsym), tx_bits(1:(nsym-d))); + else + error_positions = xor(rx_bits, tx_bits); + end + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(error_positions); + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose > 1 + figure(2) + clf + Rx = 10*log10(abs(fft(rx))); + plot(Rx(1:Fs/2)); + axis([1 Fs/2 0 50]); + + figure(3) + clf; + subplot(211) + plot(real(rx_bb(1:Ts*20))) + subplot(212) + Rx_bb = 10*log10(abs(fft(rx_bb))); + plot(Rx_bb(1:3000)); + axis([1 3000 0 50]); + + figure(4); + subplot(211) + stem(abs(mark_int(1:100))); + subplot(212) + stem(abs(space_int(1:100))); + end + + if verbose + printf("EbNo (db): %3.2f Terrs: %d BER: %3.2f \n", aEbNodB, Terrs, Terrs/Tbits); + end + end + + sim_out.TERvec = TERvec; + sim_out.BERvec = BERvec; +endfunction + + +function run_fsk_curves + sim_in.fmark = 1200; + sim_in.fspace = 2200; + sim_in.Rs = 1200; + sim_in.nsym = 12000; + sim_in.EbNodB = 0:2:20; + sim_in.fm = 0; + sim_in.verbose = 1; + + EbNo = 10 .^ (sim_in.EbNodB/10); + fsk_theory.BERvec = 0.5*exp(-EbNo/2); % non-coherent BFSK demod + fsk_sim = fsk_ber_test(sim_in); + + sim_in.fm = 1; + fsk_fm_sim = fsk_ber_test(sim_in); + + % BER v Eb/No curves + + figure(1); + clf; + semilogy(sim_in.EbNodB, fsk_theory.BERvec,'r;FSK theory;') + hold on; + semilogy(sim_in.EbNodB, fsk_sim.BERvec,'g;FSK sim;') + semilogy(sim_in.EbNodB, fsk_fm_sim.BERvec,'b;FSK over FM sim;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + + % BER v C/No (1 Hz noise BW and Eb=C/Rs=1/Rs) + % Eb/No = (C/Rs)/(1/(N/B)) + % C/N = (Eb/No)*(Rs/B) + + RsOnB_dB = 10*log10(sim_in.Rs/1); + figure(2); + clf; + semilogy(sim_in.EbNodB+RsOnB_dB, fsk_theory.BERvec,'r;FSK theory;') + hold on; + semilogy(sim_in.EbNodB+RsOnB_dB, fsk_sim.BERvec,'g;FSK sim;') + semilogy(sim_in.EbNodB+RsOnB_dB, fsk_fm_sim.BERvec,'b;FSK over FM sim;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB+RsOnB_dB) max(sim_in.EbNodB+RsOnB_dB) 1E-4 1]) + legend("boxoff"); + xlabel("C/No for Rs=1200 bit/s and 1 Hz noise bandwidth (dB)"); + ylabel("Bit Error Rate (BER)") +end + +function run_fsk_single + sim_in.fmark = 1000; + sim_in.fspace = 2000; + sim_in.Rs = 1000; + sim_in.nsym = 2000; + sim_in.EbNodB = 7; + sim_in.fm = 0; + sim_in.verbose = 1; + + fsk_sim = fsk_ber_test(sim_in); +endfunction + + +%run_fsk_curves +run_fsk_single + diff --git a/codec2/branches/0.7/octave/fsk4.m b/codec2/branches/0.7/octave/fsk4.m new file mode 100644 index 00000000..8891a455 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk4.m @@ -0,0 +1,540 @@ +% fsk4.m +% +% Brady O'Brien October 2015 +% +% 4FSK modem attempt from the DMR spec + +graphics_toolkit("gnuplot"); + +fm; % analog FM modulator functions + +pkg load signal; + +% Init function for modem ------------------------------------------------------------ + +function fsk4_states = fsk4_init(fsk4_states,fsk4_info) + Fs = fsk4_states.Fs = 48000; %Sample rate + Rs = fsk4_states.Rs = fsk4_info.rs; %Symbol rate + M = fsk4_states.M = fsk4_states.Fs/fsk4_states.Rs; %Samples per symbol + + % Set up 4FSK raised cosine filter. This probably screws up perf if we were using + % optimal mod and dmeods but helps performance when using nasty old analog FM mods + % and demods + + empty_filter = [zeros(1,99) 1]; + + rf = (0:(Fs/2)); + %If there's no filter with this modem configuration, don't bother generating one + if fsk4_info.no_filter + fsk4_states.tx_filter = empty_filter; + fsk4_states.rx_filter = empty_filter; + else + fsk4_states.tx_filter = fir2(400 ,rf/(Fs/2),fsk4_info.tx_filt_resp(rf)); + fsk4_states.rx_filter = fir2(400 ,rf/(Fs/2),fsk4_info.rx_filt_resp(rf)); + endif + + %fsk4_states.tx_filter = fsk4_states.rx_filter = [zeros(1,99) 1]; + %Set up the 4FSK symbols + fsk4_states.symmap = fsk4_info.syms / fsk4_info.max_dev; + + fm_states.Ts = M; + fm_states.Fs = Fs; + fm_states.fc = 0; + fm_states.fm_max = fsk4_info.max_dev*2; + fm_states.fd = fsk4_info.max_dev; + fm_states.pre_emp = fm_states.de_emp = 0; + fm_states.output_filter = 0; + fm_states.ph_dont_limit = 1; + fsk4_states.fm_states = analog_fm_init(fm_states); + fsk4_states.modinfo = fsk4_info; + fsk4_states.verbose = 0; +endfunction + +%Integrate over data and dump every M samples +function d = idmp(data, M) + d = zeros(1,length(data)/M); + for i = 1:length(d) + d(i) = sum(data(1+(i-1)*M:i*M)); + end +endfunction + + +% DMR modulator ---------------------------------------------------------- + +function [tx, tx_filt, tx_stream] = fsk4_mod(fsk4_states, tx_bits) + verbose = fsk4_states.verbose + + hbits = tx_bits(1:2:length(tx_bits)); + lbits = tx_bits(2:2:length(tx_bits)); + %Pad odd bit lengths + if(length(hbits)!=length(lbits)) + lbits = [lbits 0]; + end + tx_symbols = lbits + hbits*2 + 1; + M = fsk4_states.M; + nsym = length(tx_symbols); + nsam = nsym*M; + + tx_stream = zeros(1,nsam); + for i=1:nsym + tx_stream(1+(i-1)*M:i*M) = fsk4_states.symmap(tx_symbols(i)); + end + tx_filt = filter(fsk4_states.tx_filter, 1, tx_stream); + tx = analog_fm_mod(fsk4_states.fm_states, tx_filt); + + if verbose + figure(10); + plot(20*log10(abs(fft(tx)))) + title("Spectrum of modulated 4FSK") + endif + +endfunction + + +% Integrate and Dump 4FSK demod ---------------------------------------------------- + +function bits = fsk4_demod_thing(fsk4_states, rx) + + M = fsk4_states.M; + Fs = fsk4_states.Fs; + verbose = fsk4_states.verbose; + t = (0:length(rx)-1); + symup = fsk4_states.modinfo.syms; + + % Integrator is like an FIR filter with rectangular window coeffs. + % This has some nasty side lobes so lets limit the overall amount + % of noise getting in. tx filter just happens to work, but I imagine + % other LPF would as well. + + Fs = fsk4_states.Fs; + rf = (0:(Fs/2)); + rx_filter_a = fir1(100 ,.2); + rx_filter_b = fsk4_states.rx_filter; + rx_filter_n = [zeros(1,99) 1]; + + rx = filter(rx_filter_b, 1, rx); + + sym1m = exp(-j*2*pi*(symup(1)/Fs)*t).*rx; + sym2m = exp(-j*2*pi*(symup(2)/Fs)*t).*rx; + sym3m = exp(-j*2*pi*(symup(3)/Fs)*t).*rx; + sym4m = exp(-j*2*pi*(symup(4)/Fs)*t).*rx; + + % this puppy found by experiment between 1 and M. Will vary with different + % filter impulse responses, as delay will vary. f you add M to it coarse + % timing will adjust by 1. + + fine_timing = 54; + + sym1m = idmp(sym1m(fine_timing:length(sym1m)),M); sym1m = (real(sym1m).^2+imag(sym1m).^2); + sym2m = idmp(sym2m(fine_timing:length(sym2m)),M); sym2m = (real(sym2m).^2+imag(sym2m).^2); + sym3m = idmp(sym3m(fine_timing:length(sym3m)),M); sym3m = (real(sym3m).^2+imag(sym3m).^2); + sym4m = idmp(sym4m(fine_timing:length(sym4m)),M); sym4m = (real(sym4m).^2+imag(sym4m).^2); + + + figure(2); + nsym = 500; + %subplot(411); plot(sym1m(1:nsym)) + %subplot(412); plot(sym2m(1:nsym)) + %subplot(413); plot(sym3m(1:nsym)) + %subplot(414); plot(sym4m(1:nsym)) + plot((1:nsym),sym1m(1:nsym),(1:nsym),sym2m(1:nsym),(1:nsym),sym3m(1:nsym),(1:nsym),sym4m(1:nsym)) + + [x iv] = max([sym1m; sym2m; sym3m; sym4m;]); + bits = zeros(1,length(iv*2)); + figure(3); + hist(iv); + for i=1:length(iv) + bits(1+(i-1)*2:i*2) = [[0 0];[0 1];[1 0];[1 1]](iv(i),(1:2)); + end +endfunction + +function dat = bitreps(in,M) + dat = zeros(1,length(in)*M); + for i=1:length(in) + dat(1+(i-1)*M:i*M) = in(i); + end +endfunction + +% Minimal Running Disparity, 4 symbol encoder +% This is a simple 1 bit to 1 symbol encoding for 4fsk modems built +% on old fashoned FM radios. +function syms = mrd4(bits) + syms = zeros(1,length(bits)); + rd=0; + lastsym=0; + for n = (1:length(bits)) + bit = bits(n); + sp = [1 3](bit+1); %Map a bit to a +1 or +3 + [x,v] = min(abs([rd+sp rd-sp])); %Select +n or -n, whichever minimizes disparity + ssel = [sp -sp](v); + if(ssel == lastsym)ssel = -ssel;endif %never run 2 of the same syms in a row + syms(n) = ssel; %emit the symbol + rd = rd + ssel; %update running disparity + lastsym = ssel; %remember this symbol for next time + end +endfunction + +% Minimal Running Disparity, 8 symbol encoder +% This is a simple 2 bit to 1 symbol encoding for 8fsk modems built +% on old fashoned FM radios. +function syms = mrd8(bits) + bitlen = length(bits); + if mod(bitlen,2) == 1 + bits = [bits 0] + endif + + syms = zeros(1,length(bits)*.5); + rd=0; + lastsym=0; + for n = (1:2:length(bits)) + bit = (bits(n)*2)+bits(n+1); + sp = [1 3 7 5](bit+1); %Map a bit to a +1 or +3 + [x,v] = min(abs([rd+sp rd-sp])); %Select +n or -n, whichever minimizes disparity + ssel = [sp -sp](v); + if(ssel == lastsym)ssel = -ssel;endif %never run 2 of the same syms in a row + syms((n+1)/2) = ssel; %emit the symbol + rd = rd + ssel; %update running disparity + lastsym = ssel; %remember this symbol for next time + end +endfunction + +% "Manchester 4" encoding +function syms = mane4(bits) + syms = zeros(1,floor(bits/2)*2); + for n = (1:2:length(bits)) + bit0 = bits(n); + bit1 = bits(n+1); + sel = 2*bit0+bit1+1; + syms(n:n+1) = [[3 -3];[-3 3];[1 -1];[-1 1]]( sel,(1:2) ); + end +endfunction + +function out = fold_sum(in,l) + sublen = floor(length(in)/l); + out = zeros(1,l); + for i=(1:sublen) + v = in(1+(i-1)*l:i*l); + out = out + v; + end +endfunction + +function [bits err rxphi] = fsk4_demod_fmrid(fsk4_states, rx, enable_fine_timing = 0) + %Demodulate fsk signal with an analog fm demod + rxd = analog_fm_demod(fsk4_states.fm_states,rx); + + M = fsk4_states.M; + verbose = fsk4_states.verbose; + %This is the ideal fine timing, assuming the same offset in nfbert + fine_timing = 61; + + %This is meant to be adjusted by the fine timing estimator. comment out for + %ideal timing + %fine_timing = 59; + + %RRC filter to get rid of some of the noise + rxd = filter(fsk4_states.rx_filter, 1, rxd); + + %Try and figure out where sampling should happen over 30 symbol periods + diffsel = fold_sum(abs(diff( rxd(3001:3001+(M*30)) )),10); + + if verbose + figure(11); + plot(diffsel); + title("Fine timing estimation"); + endif + + %adjust fine timing + [v iv] = min(diffsel); + if enable_fine_timing + fine_timing = 59 + iv; + endif + rxphi = iv; + + %sample symbols + sym = rxd(fine_timing:M:length(rxd)); + + if verbose + figure(4) + plot(sym(1:1000)); + title("Sampled symbols") + endif + %eyediagram(afsym,2); + % Demod symbol map. I should probably figure a better way to do this. + % After sampling, the furthest symbols tend to be distributed about .80 + + % A little cheating to demap the symbols + % Take a histogram of the sampled symbols, find the center of the largest distribution, + % and correct the symbol map to match it + [a b] = hist(abs(sym),50); + [a ii] = max(a); + %grmax = abs(b(ii)); + %grmax = (grmax<.65)*.65 + (grmax>=.65)*grmax; + grmax = .84; + dmsyms = rot90(fsk4_states.symmap*grmax) + (dmsyms(2)+dmsyms(1))/2 + + if verbose + figure(2) + hist(abs(sym),200); + title("Sampled symbol histogram") + endif + + %demap the symbols + [err, symout] = min(abs(sym-dmsyms)); + + if verbose + figure(3) + hist(symout); + title("De-mapped symbols") + endif + + bits = zeros(1,length(symout)*2); + %Translate symbols back into bits + + for i=1:length(symout) + bits(1+(i-1)*2:i*2) = [[1 1];[1 0];[0 1];[0 0]](symout(i),(1:2)); + end +endfunction + +% Frequency response of the DMR raised cosine filter +% from ETSI TS 102 361-1 V2.2.1 page 111 +dmr.tx_filt_resp = @(f) sqrt(1.0*(f<=1920) - cos((pi*f)/1920).*1.0.*(f>1920 & f<=2880)); +dmr.rx_filt_resp = dmr.tx_filt_resp; +dmr.max_dev = 1944; +dmr.syms = [-1944 -648 1944 648]; +dmr.rs = 4800; +dmr.no_filter = 0; +dmr.demod_fx = @fsk4_demod_fmrid; +global dmr_info = dmr; + + +% No-filter 4FSK 'ideal' parameters +nfl.tx_filt_resp = @(f) 1; +nfl.rx_filt_resp = nfl.tx_filt_resp; +nfl.max_dev = 7200; +%nfl.syms = [-3600 -1200 1200 3600]; +nfl.syms = [-7200,-2400,2400,7200]; +nfl.rs = 4800; +nfl.no_filter = 1; +nfl.demod_fx = @fsk4_demod_thing; +global nflt_info = nfl; + +%Some parameters for the NXDN filters +nxdn_al = .2; +nxdn_T = 416.7e-6; +nxdn_fl = ((1-nxdn_al)/(2*nxdn_T)); +nxdn_fh = ((1+nxdn_al)/(2*nxdn_T)); + +%Frequency response of the NXDN filters +% from NXDN TS 1-A V1.3 page 13 +% Please note : NXDN not fully implemented or tested +nxdn_H = @(f) 1.0*(fnxdn_fl); +nxdn_P = @(f) (f<=nxdn_fh & f>0).*((sin(pi*f*nxdn_T))./(.00001+(pi*f*nxdn_T))) + 1.0*(f==0); +nxdn_D = @(f) (f<=nxdn_fh & f>0).*((pi*f*nxdn_T)./(.00001+sin(pi*f*nxdn_T))) + 1.0*(f==0); + +nxdn.tx_filt_resp = @(f) nxdn_H(f).*nxdn_P(f); +nxdn.rx_filt_resp = @(f) nxdn_H(f).*nxdn_D(f); +nxdn.rs = 4800; +nxdn.max_dev = 1050; +nxdn.no_filter = 0; +nxdn.syms = [-1050,-350,350,1050]; +nxdn.demod_fx = @fsk4_demod_fmrid; +global nxdn_info = nxdn; + +% Bit error rate test ---------------------------------------------------------- +% Params - aEsNodB - EbNo in decibels +% - timing_offset - how far the fine timing is offset +% - bitcnt - how many bits to check +% - demod_fx - demodulator function +% Returns - ber - teh measured BER +% - thrcoh - theory BER of a coherent demod +% - thrncoh - theory BER of non-coherent demod +function [ber thrcoh thrncoh] = nfbert(aEsNodB,modem_config, bitcnt=100000, timing_offset = 10) + + rand('state',1); + randn('state',1); + + %How many bits should this test run? + bitcnt = 120000; + + test_bits = [zeros(1,100) rand(1,bitcnt)>.5]; %Random bits. Pad with zeros to prime the filters + fsk4_states.M = 1; + fsk4_states = fsk4_init(fsk4_states,modem_config); + + %Set this to 0 to cut down on the plotting + fsk4_states.verbose = 1; + Fs = fsk4_states.Fs; + Rb = fsk4_states.Rs * 2; % Multiply symbol rate by 2, since we have 2 bits per symbol + + tx = fsk4_mod(fsk4_states,test_bits); + + %add noise here + %shamelessly copied from gmsk.m + EsNo = 10^(aEsNodB/10); + EbNo = EsNo + variance = Fs/(Rb*EbNo); + nsam = length(tx); + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx*exp(j*pi/2) + noise; + + rx = rx(timing_offset:length(rx)); + + rx_bits = modem_config.demod_fx(fsk4_states,rx); + ber = 1; + + %thing to account for offset from input data to output data + %No preamble detection yet + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),test_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + printf("\ncoarse timing: %d nerr: %d\n", offset, best_nerr); + + % Coherent BER theory + thrcoh = erfc(sqrt(EbNo)); + + % non-coherent BER theory calculation + % It was complicated, so I broke it up + + ms = 4; + ns = (1:ms-1); + as = (-1).^(ns+1); + bs = (as./(ns+1)); + + cs = ((ms-1)./ns); + + ds = ns.*log2(ms); + es = ns+1; + fs = exp( -(ds./es)*EbNo ); + + thrncoh = ((ms/2)/(ms-1)) * sum(bs.*((ms-1)./ns).*exp( -(ds./es)*EbNo )); + +endfunction + +% RX fine timing estimation playground +function rxphi = fine_ex(timing_offset = 1) + global dmr_info; + global nxdn_info; + global nflt_info; + + rand('state',1); + randn('state',1); + + bitcnt = 12051; + test_bits = [zeros(1,100) rand(1,bitcnt)>.5]; %Random bits. Pad with zeros to prime the filters + t_vec = [0 0 1 1]; + %test_bits = repmat(t_vec,1,ceil(24000/length(t_vec))); + + + fsk4_states.M = 1; + fsk4_states = fsk4_init(fsk4_states,dmr_info); + Fs = fsk4_states.Fs; + Rb = fsk4_states.Rs * 2; %Multiply symbol rate by 2, since we have 2 bits per symbol + + tx = fsk4_mod(fsk4_states,test_bits); + + %add noise here + %shamelessly copied from gmsk.m + %EsNo = 10^(aEsNodB/10); + %EbNo = EsNo + %variance = Fs/(Rb*EbNo); + %nsam = length(tx); + %noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + %rx = tx*exp(j*pi/2) + noise; + rx = tx; + rx = rx(timing_offset:length(rx)); + + [rx_bits biterr rxphi] = fsk4_demod_fmrid(fsk4_states,rx); + ber = 1; + + %thing to account for offset from input data to output data + %No preamble detection yet + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),test_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + printf("\ncoarse timing: %d nerr: %d\n", offset, best_nerr); + +endfunction + +%Run over a wide range of offsets and make sure fine timing makes sense +function fsk4_rx_phi(socket) + %pkg load parallel + offrange = [100:200]; + [a b c phi] = pararrayfun(1.25*nproc(),@nfbert,10*length(offrange),offrange); + + close all; + figure(1); + clf; + plot(offrange,phi); +endfunction + + +% Run this function to compare the theoretical 4FSK modem performance +% with our DMR modem simulation + +function fsk4_ber_curves + global dmr_info; + global nxdn_info; + global nflt_info; + + EbNodB = 1:20; + bers_tco = bers_real = bers_tnco = bers_idealsim = ones(1,length(EbNodB)); + + %vectors of the same param to pass into pararrayfun + dmr_infos = repmat(dmr_info,1,length(EbNodB)); + nflt_infos = repmat(nflt_info,1,length(EbNodB)); + thing = @fsk4_demod_thing; + + % Lovely innovation by Brady to use all cores and really speed up the simulation + + %try + pkg load parallel + bers_idealsim = pararrayfun(floor(1.25*nproc()),@nfbert,EbNodB,nflt_infos); + [bers_real,bers_tco,bers_tnco] = pararrayfun(floor(1.25*nproc()),@nfbert,EbNodB,dmr_infos); + %catch + % printf("You should install package parallel. It'll make this run way faster\n"); + % for ii=(1:length(EbNodB)); + %[bers_real(ii),bers,tco(ii),bers_tnco(ii)] = nfbert(EbNodB(ii)); + % end + %end_try_catch + + close all + figure(1); + clf; + semilogy(EbNodB, bers_tnco,'r;4FSK non-coherent theory;') + hold on; + + semilogy(EbNodB, bers_tco,'b;4FSK coherent theory;') + semilogy(EbNodB, bers_real ,'g;4FSK DMR simulation;') + semilogy(EbNodB, bers_idealsim, 'v;FSK4 Ideal Non-coherent simulation;') + hold off; + grid("minor"); + axis([min(EbNodB) max(EbNodB) 1E-5 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + +endfunction + + + + + + + + diff --git a/codec2/branches/0.7/octave/fsk_basic.m b/codec2/branches/0.7/octave/fsk_basic.m new file mode 100644 index 00000000..1b06cd86 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_basic.m @@ -0,0 +1,60 @@ +% fsk_basic.m +% David Rowe 30 sep 2016 +% +% Basic non-coherence FSK modem simulation to illustrate principles +% and compare to ideal + +rand('seed',1); +randn('seed',1); + +Fs = 9600; % sample rate +f1 = 1200; +f2 = 2400; +Rs = 1200; % symbol rate +Ts = Fs/Rs; % length of each symbol in samples +Nbits = 10000; +EbNodB = 9; + +tx_bits = round(rand(1,Nbits)); + +% continuous phase FSK modulator + +w1 = 2*pi*f1/Fs; +w2 = 2*pi*f2/Fs; +tx_phase = 0; +tx = zeros(1,Ts*Nbits); + +for i=1:Nbits + for k=1:Ts + if tx_bits(i) + tx_phase += w2; + else + tx_phase += w1; + end + tx((i-1)*Ts+k) = exp(j*tx_phase); + end +end + +% AWGN channel noise + +EbNo = 10^(EbNodB/10); +variance = Fs/(Rs*EbNo); +noise = sqrt(variance/2)*(randn(1,Nbits*Ts) + j*randn(1,Nbits*Ts)); +rx = tx + noise; + +% integrate and dump demodulator + +rx_bits = zeros(1,Nbits); +for i=1:Nbits + arx_symb = rx((i-1)*Ts + (1:Ts)); + filt1 = sum(exp(-j*w1*(1:Ts)) .* arx_symb); + filt2 = sum(exp(-j*w2*(1:Ts)) .* arx_symb); + rx_bits(i) = filt2 > filt1; +end + +Nerrors = sum(xor(tx_bits, rx_bits)); +ber = Nerrors/Nbits; +printf("EbNodB: %4.1f Nerrors: %d BER: %1.3f\n", EbNodB, Nerrors, ber); + + + diff --git a/codec2/branches/0.7/octave/fsk_cont_phase.m b/codec2/branches/0.7/octave/fsk_cont_phase.m new file mode 100644 index 00000000..d6b4e9d1 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_cont_phase.m @@ -0,0 +1,85 @@ +% fsk_cont_phase.m +% David Rowe Feb 2016 +% +% Looking at tx spectrum of FSK signal with and without continuous phase in the +% modulator. + +1; + +function tx = fsk_mod(states, tx_bits) + + M = states.M; + Ts = states.Ts; + Fs = states.Fs; + ftx = states.ftx; + phase_cont = states.phase_cont; + + num_bits = length(tx_bits); + num_symbols = num_bits; + tx = zeros(states.Ts*num_symbols,1); + tx_phase = 0; + s = 1; + + for i=1:num_bits + + % map bits to tone number + + tone = tx_bits(i) + 1; + + if phase_cont + tx_phase_vec = tx_phase + (1:Ts)*2*pi*ftx(tone)/Fs; + tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi; + else + tx_phase_vec = (1:Ts)*2*pi*ftx(tone)/Fs; + end + + tx((s-1)*Ts+1:s*Ts) = 2.0*cos(tx_phase_vec); + s++; + %printf("phase_cont: %d tx_phase_vec(Ts): %f\n", phase_cont, tx_phase_vec(Ts)); + + end +endfunction + + +states.Fs = 8000; +states.Rs = 100; +states.Ts = states.Fs/states.Rs; +states.M = 2; +states.ftx = [1200 1305]; % need to choose these carefullto get disc phase + +Nbits = 1024; + +tx_bits = rand(1,Nbits) > 0.5; +%tx_bits = [0 1 0]; + +states.phase_cont = 1; +tx_cont = fsk_mod(states, tx_bits); + +states.phase_cont = 0; +tx_disc = fsk_mod(states, tx_bits); + +figure(1) +clf +plot(tx_cont(1:states.Ts*4)) +hold on; +plot(tx_disc(1:states.Ts*4),'g') +hold off; +title('Time Domain') + +figure(2) +clf +subplot(211) +Tx_cont = fft(tx_cont); +Tx_cont_dB = 20*log10(abs(Tx_cont)); +plot(Tx_cont_dB) +axis([1 length(Tx_cont_dB)/2 0 100]); +grid +title('Cont Phase Spectra') + +Tx_disc = fft(tx_disc); +Tx_disc_dB = 20*log10(abs(Tx_disc)); +subplot(212) +plot(Tx_disc_dB,'g') +axis([1 length(Tx_cont_dB)/2 0 100]); +grid +title('Disc Cont Phase Spectra') diff --git a/codec2/branches/0.7/octave/fsk_eme.m b/codec2/branches/0.7/octave/fsk_eme.m new file mode 100644 index 00000000..47e57a23 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_eme.m @@ -0,0 +1,377 @@ +% fsk_eme.m +% David Rowe July 2017 +% +% FSK modem for digital voice over 1296 MHz Earth-Moon-Earth (EME) links + +fsk_lib; + +function run_sim(frames = 10, EbNodB = 100) + Fs = 8000; Rs = 8; M = 16; Fsep = 50; + + timing_offset = 0.0; % see resample() for clock offset below + fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + df = 0; % tx tone freq drift in Hz/s + dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',1); + randn('state',1); + + states = fsk_init(Fs, 50, M); + + states.ftx = 1000 + Fsep*(-M/2:M/2-1); + + % ---------------------------------------------------------------------- + + states.verbose = 0x1; + M = states.M; + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + nbit = states.nbit; + Fs = states.Fs; + states.df(1:M) = df; + states.dA(1:M) = dA; + + % optional noise. Useful for testing performance of waveforms from real world modulators + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % test frame of bits, which we repeat for convenience when BER testing + + states.ntestframebits = states.nbit; + test_frame = round(rand(1, states.ntestframebits)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + + + tx = fsk_mod(states, tx_bits); + + %tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + printf("SNRdB meas: %4.1f\n", 10*log10(var(tx)/var(noise))); + + % dump simulated rx file + + g = 1000; + ftx=fopen("fsk_horus_tx.raw","wb"); txg = tx*g; fwrite(ftx, txg, "short"); fclose(ftx); + frx=fopen("fsk_horus_rx.raw","wb"); rxg = rx*g; fwrite(frx, rxg, "short"); fclose(frx); + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,nbit+states.ntestframebits); + x_log = []; + timing_nl_log = []; + norm_rx_timing_log = []; + f_int_resample_log = []; + f_log = []; + EbNodB_log = []; + rx_bits_log = []; + rx_bits_sd_log = []; + + % main loop --------------------------------------------------------------- + + run_frames = floor(length(rx)/N)-1; + for f=1:run_frames + + % extract nin samples from input stream + + nin = states.nin; + en = st + states.nin - 1; + + if en < length(rx) % due to nin variations its possible to overrun buffer + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + states = est_freq(states, sf, states.M); + states.f = states.ftx; + [rx_bits states] = fsk_demod(states, sf); + + rx_bits_buf(1:states.ntestframebits) = rx_bits_buf(nbit+1:states.ntestframebits+nbit); + rx_bits_buf(states.ntestframebits+1:states.ntestframebits+nbit) = rx_bits; + %rx_bits_buf(1:nbit) = rx_bits_buf(nbit+1:2*nbit); + %rx_bits_buf(nbit+1:2*nbit) = rx_bits; + + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + x_log = [x_log states.x]; + timing_nl_log = [timing_nl_log states.timing_nl]; + f_int_resample_log = [f_int_resample_log abs(states.f_int_resample(:,:))]; + f_log = [f_log; states.f]; + EbNodB_log = [EbNodB_log states.EbNodB]; + + states = ber_counter(states, test_frame, rx_bits_buf); + end + end + + % print stats, count errors, decode packets ------------------------------------------ + + printf("frames: %d EbNo: %3.2f Tbits: %d Terrs: %d BER %4.3f\n", frames, EbNodB, states.Tbits,states. Terrs, states.Terrs/states.Tbits); + + figure(1); + plot(f_int_resample_log','+') + hold off; + + figure(2) + clf + m = max(abs(x_log)); + plot(x_log,'+') + axis([-m m -m m]) + title('fine timing metric') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log); + axis([1 run_frames -1 1]) + title('norm fine timing') + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(4) + clf + subplot(211) + one_sec_rx = rx(1:min(Fs,length(rx))); + plot(one_sec_rx) + title('rx signal at demod input') + subplot(212) + plot(abs(fft(one_sec_rx))) + + figure(5) + clf + plot(f_log,'+') + title('tone frequencies') + axis([1 run_frames 0 Fs/2]) + + figure(6) + clf + plot(EbNodB_log); + title('Eb/No estimate') + + figure(7) + clf + subplot(211) + X = abs(fft(timing_nl_log)); + plot(X(1:length(X)/2)) + subplot(212) + plot(abs(timing_nl_log(1:100))) + + endfunction + + +% demodulate a file of 8kHz 16bit short samples -------------------------------- + +function rx_bits_log = demod_file(filename, test_frame_mode, noplot=0, EbNodB=100) + fin = fopen(filename,"rb"); + more off; + + %states = fsk_horus_init(96000, 1200); + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100, 2); + uwstates = fsk_horus_init_rtty_uw(states); + states.ntestframebits = states.nbits; + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 50, 4); + uwstates = fsk_horus_init_binary_uw; + states.ntestframebits = states.nbits; + end + + states.verbose = 0x1 + 0x8; + + if test_frame_mode == 6 + % Horus high speed config -------------- + states = fsk_horus_init_hbr(9600, 8, 1200, 2, 16); + states.tx_bits_file = "horus_high_speed.bin"; + states.verbose += 0x4; + ftmp = fopen(states.tx_bits_file, "rb"); test_frame = fread(ftmp,Inf,"char")'; fclose(ftmp); + states.ntestframebits = length(test_frame); + printf("length test frame: %d\n", states.ntestframebits); + end + + if test_frame_mode == 7 + % 800XA 4FSK modem -------------- + states = fsk_horus_init_hbr(8000, 10, 400, 4, 256); + states.tx_bits_file = "horus_high_speed.bin"; + states.verbose += 0x4; + ftmp = fopen(states.tx_bits_file, "rb"); test_frame = fread(ftmp,Inf,"char")'; fclose(ftmp); + states.ntestframebits = length(test_frame); + printf("length test frame: %d\n", states.ntestframebits); + end + + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + nbit = states.nbit; + + frames = 0; + rx = []; + rx_bits_log = []; + rx_bits_sd_log = []; + norm_rx_timing_log = []; + f_int_resample_log = []; + EbNodB_log = []; + ppm_log = []; + f_log = []; + rx_bits_buf = zeros(1,nbit + states.ntestframebits); + + % optional noise. Useful for testing performance of waveforms from real world modulators + + EbNo = 10^(EbNodB/10); + ftmp = fopen(filename,"rb"); s = fread(ftmp,Inf,"short"); fclose(ftmp); tx_pwr = var(s); + variance = (tx_pwr/2)*states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % First extract raw bits from samples ------------------------------------------------------ + + printf("demod of raw bits....\n"); + + finished = 0; + while (finished == 0) + + % extract nin samples from input stream + + nin = states.nin; + [sf count] = fread(fin, nin, "short"); + rx = [rx; sf]; + + % add optional noise + + if count + noise = sqrt(variance)*randn(count,1); + sf += noise; + end + + if count == nin + frames++; + + % demodulate to stream of bits + + states = est_freq(states, sf, states.M); + %states.f = [1450 1590 1710 1850]; + [rx_bits states] = fsk_horus_demod(states, sf); + + rx_bits_buf(1:states.ntestframebits) = rx_bits_buf(nbit+1:states.ntestframebits+nbit); + rx_bits_buf(states.ntestframebits+1:states.ntestframebits+nbit) = rx_bits; + + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + f_int_resample_log = [f_int_resample_log abs(states.f_int_resample)]; + EbNodB_log = [EbNodB_log states.EbNodB]; + ppm_log = [ppm_log states.ppm]; + f_log = [f_log; states.f]; + + if test_frame_mode == 1 + states = ber_counter(states, test_frame, rx_bits_buf); + if states.ber_state == 1 + states.verbose = 0; + end + end + if test_frame_mode == 6 + states = ber_counter_packet(states, test_frame, rx_bits_buf); + end + else + finished = 1; + end + end + fclose(fin); + + if noplot == 0 + printf("plotting...\n"); + + figure(1); + plot(f_log); + hold off; + + figure(2); + plot(f_int_resample_log','+') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log) + axis([1 frames -0.5 0.5]) + title('norm fine timing') + grid + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(4) + clf + plot(EbNodB_log); + title('Eb/No estimate') + + figure(5) + clf + rx_nowave = rx(1000:length(rx)); + subplot(211) + plot(rx_nowave(1:states.Fs)); + title('input signal to demod (1 sec)') + xlabel('Time (samples)'); + axis([1 states.Fs -35000 35000]) + + % normalise spectrum to 0dB full scale with a 32767 sine wave input + + subplot(212) + RxdBFS = 20*log10(abs(fft(rx_nowave(1:states.Fs)))) - 20*log10((states.Fs/2)*32767); + plot(RxdBFS) + axis([1 states.Fs/2 -80 0]) + xlabel('Frequency (Hz)'); + + figure(6); + clf + plot(ppm_log) + title('Sample clock (baud rate) offset in PPM'); + end + + if (test_frame_mode == 1) || (test_frame_mode == 6) + printf("frames: %d Tbits: %d Terrs: %d BER %4.3f EbNo: %3.2f\n", frames, states.Tbits,states. Terrs, states.Terrs/states.Tbits, mean(EbNodB_log)); + end + + % we can decode both protocols at the same time + + if (test_frame_mode == 4) || (test_frame_mode == 5) + extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + corr_log = extract_and_decode_binary_packets(states, rx_bits_log); + + figure(8); + clf + plot(corr_log); + hold on; + plot([1 length(corr_log)],[states.binary.uw_thresh states.binary.uw_thresh],'g'); + hold off; + title('UW correlation'); + end + +endfunction + + +% Start simulations here ------------------------------------------------------------- + +more off; format; + +%run_sim(1, 2, 100, 9); +run_sim(10, 20); diff --git a/codec2/branches/0.7/octave/fsk_horus.m b/codec2/branches/0.7/octave/fsk_horus.m new file mode 100644 index 00000000..eb44fda9 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_horus.m @@ -0,0 +1,803 @@ +% fsk_horus.m +% David Rowe 10 Oct 2015 +% +% Project Horus High Altitude Balloon (HAB) FSK demodulator +% See blog write up "All your modems are belong to us" +% http://www.rowetel.com/?p=4629 + + +fsk_lib; + + +function states = fsk_horus_init(Fs,Rs,M=2) + + states = fsk_init(Fs,Rs,M); + states.rtty = fsk_horus_init_rtty_uw(states); + states.binary = fsk_horus_init_binary_uw; + + % Freq. estimator limits - keep these narrow to stop errors with low SNR 4FSK + + states.fest_fmin = 800; + states.fest_fmax = 2500; + states.fest_min_spacing = 200; + +endfunction + + +% init rtty protocol specifc states + +function rtty = fsk_horus_init_rtty_uw(states) + % Generate unque word that correlates against the ASCII "$$$$$" that + % is at the start of each frame. + % $ -> 36 decimal -> 0 1 0 0 1 0 0 binary + + dollar_bits = fliplr([0 1 0 0 1 0 0]); + mapped_db = 2*dollar_bits - 1; + sync_bits = [1 1 0]; + mapped_sb = 2*sync_bits - 1; + %mapped_sb = [ 0 0 0 ]; + + mapped = [mapped_db mapped_sb]; + npad = rtty.npad = 3; % one start and two stop bits between 7 bit ascii chars + nfield = rtty.nfield = 7; % length of ascii character field + + rtty.uw = [mapped mapped mapped mapped mapped]; + rtty.uw_thresh = length(rtty.uw) - 2; % allow a few bit errors when looking for UW + rtty.max_packet_len = 1000; +endfunction + + +% I think this is the binary protocol work from Jan 2016 + +function binary = fsk_horus_init_binary_uw + % Generate 16 bit "$$" unique word that is at the front of every horus binary + % packet + + dollar_bits = [0 0 1 0 0 1 0 0]; + mapped_db = 2*dollar_bits - 1; + + binary.uw = [mapped_db mapped_db]; + binary.uw_thresh = length(binary.uw)-2; % no bit errors when looking for UW + + binary.max_packet_len = 360; +endfunction + + +% Look for unique word and return index of first UW bit, or -1 if no +% UW found Sometimes there may be several matches, returns the +% position of the best match to UW. + +function [uw_start best_corr corr] = find_uw(states, start_bit, rx_bits) + uw = states.uw; + + mapped_rx_bits = 2*rx_bits - 1; + best_corr = 0; + uw_start = -1; + found_uw = 0; + + % first first UW in buffer that exceeds threshold + + for i=start_bit:length(rx_bits) - length(uw) + corr(i) = mapped_rx_bits(i:i+length(uw)-1) * uw'; + if (found_uw == 0) && (corr(i) >= states.uw_thresh) + uw_start = i; + best_corr = corr; + found_uw = 1; + end + end + +endfunction + + +% Extract ASCII string from a Horus frame of bits + +function [str crc_ok] = extract_ascii(states, rx_bits_buf, uw_loc) + nfield = states.nfield; + npad = states.npad; + + str = []; str_dec = []; nstr = 0; ptx_crc = 1; rx_crc = ""; + endpacket = 0; + + st = uw_loc + length(states.uw); % first bit of first char + en = uw_loc + states.max_packet_len - nfield; + %printf("\nst: %d en: %d len: %d\n", st, en, length(rx_bits_buf)); + + for i=st:nfield+npad:en + field = rx_bits_buf(i:i+nfield-1); + ch_dec = field * (2.^(0:nfield-1))'; + + % filter out unlikely characters that bit errors may introduce, and ignore \n + + if (ch_dec > 31) && (ch_dec < 91) + str = [str char(ch_dec)]; + else + str = [str char(32)]; % space is "not sure" + end + nstr++; + + % build up array for CRC16 check + + if !endpacket && (ch_dec == 42) + endpacket = 1; + rx_crc = crc16(str_dec); % found a '*' so that's the end of the string for CRC calculations + ptx_crc = nstr+1; % this is where the transmit CRC starts + end + if !endpacket + str_dec = [str_dec ch_dec]; + end + end + + if (ptx_crc+3) <= length(str) + tx_crc = str(ptx_crc:ptx_crc+3); + crc_ok = strcmp(tx_crc, rx_crc); + else + crc_ok = 0; + end + + str = str(1:ptx_crc-2); + +endfunction + + +% Use soft decision information to find bits most likely in error. I think +% this is some form of maximum likelihood decoding. + +function [str crc_ok rx_bits_log_flipped] = sd_bit_flipping(states, rx_bits_log, rx_bits_sd_log, st, en); + + % force algorithm to ignore rs232 sync bits by marking them as "very likely", they have + % no input to crc algorithm + + nfield = states.nfield; + npad = states.npad; + for i=st:nfield+npad:en + rx_bits_sd_log(i+nfield:i+nfield+npad-1) = 1E6; + end + + % make a list of bits with smallest soft decn values + + [dodgy_bits_mag dodgy_bits_index] = sort(abs(rx_bits_sd_log(st+length(states.uw):en))); + dodgy_bits_index += length(states.uw) + st - 1; + nbits = 6; + ntries = 2^nbits; + str = ""; + crc_ok = 0; + + % try various combinations of these bits + + for i=1:ntries-1 + error_mask = zeros(1, length(rx_bits_log)); + for b=1:nbits + x = bitget(i,b); + bit_to_flip = dodgy_bits_index(b); + error_mask(bit_to_flip) = x; + %printf("st: %d i: %d b: %d x: %d index: %d\n", st, i,b,x,bit_to_flip); + end + rx_bits_log_flipped = xor(rx_bits_log, error_mask); + [str_flipped crc_ok_flipped] = extract_ascii(states, rx_bits_log_flipped, st); + if crc_ok_flipped + %printf("Yayy we fixed a packet by flipping with pattern %d\n", i); + str = str_flipped; + crc_ok = crc_ok_flipped; + end + end +endfunction + + +% Extract as many ASCII packets as we can from a great big buffer of bits + +function extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + + % use UWs to delimit start and end of data packets + + bit = 1; + nbits = length(rx_bits_log); + nfield = states.rtty.nfield; + npad = states.rtty.npad; + + uw_loc = find_uw(states.rtty, bit, rx_bits_log, states.verbose); + + while (uw_loc != -1) + + if (uw_loc + states.rtty.max_packet_len) < nbits + % Now start picking out 7 bit ascii chars from frame. It has some + % structure so we can guess where fields are. I hope we don't get + % RS232 idle bits stuck into it anywhere, ie "bit fields" don't + % change dynamically. + + % dump msg bits so we can use them as a test signal + %msg = rx_bits_log(st:uw_loc-1); + %save -ascii horus_msg.txt msg + + % simulate bit error for testing + %rx_bits_log(st+200) = xor(rx_bits_log(st+100),1); + %rx_bits_sd_log(st+100) = 0; + + [str crc_ok] = extract_ascii(states.rtty, rx_bits_log, uw_loc); + + if crc_ok == 0 + [str_flipped crc_flipped_ok rx_bits_log] = sd_bit_flipping(states.rtty, rx_bits_log, rx_bits_sd_log, uw_loc, uw_loc+states.rtty.max_packet_len); + end + + % update memory of previous packet, we use this to guess where errors may be + if crc_ok || crc_flipped_ok + states.prev_pkt = rx_bits_log(uw_loc+length(states.rtty.uw):uw_loc+states.rtty.max_packet_len); + end + + if crc_ok + str = sprintf("%s CRC OK", str); + else + if crc_flipped_ok + str = sprintf("%s fixed", str_flipped); + else + str = sprintf("%s CRC BAD", str); + end + end + printf("%s\n", str); + end + + % look for next packet + + bit = uw_loc + length(states.rtty.uw); + uw_loc = find_uw(states.rtty, bit, rx_bits_log, states.verbose); + + endwhile +endfunction + + +% Extract as many binary packets as we can from a great big buffer of bits, +% and send them to the C decoder for FEC decoding. +% horus_l2 can be compiled a bunch of different ways. You need to +% compile with: +% codec2-dev/src$ gcc horus_l2.c -o horus_l2 -Wall -DDEC_RX_BITS -DHORUS_L2_RX + +function corr_log = extract_and_decode_binary_packets(states, rx_bits_log) + corr_log = []; + + % use UWs to delimit start and end of data packets + + bit = 1; + nbits = length(rx_bits_log); + + [uw_loc best_corr corr] = find_uw(states.binary, bit, rx_bits_log, states.verbose); + corr_log = [corr_log corr]; + + while (uw_loc != -1) + + if (uw_loc+states.binary.max_packet_len) < nbits + % printf("uw_loc: %d best_corr: %d\n", uw_loc, best_corr); + + % OK we have a packet delimited by two UWs. Lets convert the bit + % stream into bytes and save for decoding + + pin = uw_loc; + for i=1:45 + rx_bytes(i) = rx_bits_log(pin:pin+7) * (2.^(7:-1:0))'; + pin += 8; + %printf("%d 0x%02x\n", i, rx_bytes(i)); + end + + f=fopen("horus_rx_bits_binary.bin","wb"); + fwrite(f, rx_bytes, "uchar"); + fclose(f); + + % optionally write packet to disk to use as horus_tx_bits_binary.txt + f=fopen("horus_rx_bits_binary.txt","wt"); + for i=uw_loc:uw_loc+45*8-1 + fprintf(f, "%d ", rx_bits_log(i)); + end + fclose(f); + + system("../src/horus_l2"); % compile instructions above + end + + bit = uw_loc + length(states.binary.uw); + [uw_loc best_corr corr] = find_uw(states.binary, bit, rx_bits_log, states.verbose); + corr_log = [corr_log corr]; + + endwhile +endfunction + + +% simulation of tx and rx side, add noise, channel impairments ---------------------- +% +% test_frame_mode Description +% 1 BER testing using known test frames +% 2 random bits +% 3 repeating sequence of all symbols +% 4 Horus RTTY +% 5 Horus Binary +% 6 Horus High Speed: A 8x oversampled modem, e.g. Fs=9600, Rs=1200 +% which is the same as Fs=921600 Rs=115200 +% Uses packet based BER counter + +function run_sim(test_frame_mode, M=2, frames = 10, EbNodB = 100) + timing_offset = 0.0; % see resample() for clock offset below + fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + df = 0; % tx tone freq drift in Hz/s + dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',1); + randn('state',1); + + % ---------------------------------------------------------------------- + + % sm2000 config ------------------------ + %states = fsk_horus_init(96000, 1200); + %states.f1_tx = 4000; + %states.f2_tx = 5200; + + if test_frame_mode < 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 50, M); + %states = fsk_horus_init_hbr(8000, 10, 400, 4); % EME + end + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100); + states.tx_bits_file = "horus_tx_bits_rtty.txt"; % Octave file of bits we FSK modulate + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 50, 4); + states.tx_bits_file = "horus_tx_bits_binary.txt"; % Octave file of bits we FSK modulate + end + + if test_frame_mode == 6 + % horus high speed --------------------- + states = fsk_horus_init_hbr(9600, 8, 1200, 2, 16); + states.tx_bits_file = "horus_high_speed.bin"; + end + + % Tones must be at least Rs apart for ideal non-coherent FSK + + #{ + if states.M == 2 + states.ftx = 1200 + [ 0 2*states.Rs ]; + else + states.ftx = 1200 + 2*states.Rs*(1:4); + %states.ftx = 200 + states.Rs*(1:4); % EME + end + #} + states.ftx = 900 + 2*states.Rs*(1:states.M); + + % ---------------------------------------------------------------------- + + states.verbose = 0x1; + M = states.M; + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + nbit = states.nbit; + Fs = states.Fs; + states.df(1:M) = df; + states.dA(1:M) = dA; + + % optional noise. Useful for testing performance of waveforms from real world modulators + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % set up tx signal with payload bits based on test mode + + if (test_frame_mode == 1) + % test frame of bits, which we repeat for convenience when BER testing + states.ntestframebits = states.nbit; + test_frame = round(rand(1, states.ntestframebits)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nbit*(frames+1))); + end + + if test_frame_mode == 3 + % repeating sequence of all symbols + % great for initial test of demod if nothing else works, + % look for this pattern in rx_bits + if M == 2 + % ...10101... + tx_bits = zeros(1, states.nbit*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + else + % repeat each possible 4fsk symbol + pattern = [0 0 0 1 1 0 1 1]; + %pattern = [0 0 0 1 1 1 1 0]; + nrepeats = states.nbit*(frames+1)/length(pattern); + tx_bits = []; + for b=1:nrepeats + tx_bits = [tx_bits pattern]; + end + %tx_bits = zeros(1, states.nbit*(frames+1)); + end + end + + if (test_frame_mode == 4) || (test_frame_mode == 5) + + % load up a horus msg from disk and modulate that + + test_frame = load(states.tx_bits_file); + ltf = length(test_frame); + ntest_frames = ceil((frames+1)*nbit/ltf); + tx_bits = []; + for i=1:ntest_frames + tx_bits = [tx_bits test_frame]; + end + end + + if test_frame_mode == 6 + states.verbose += 0x4; + ftmp = fopen(states.tx_bits_file, "rb"); test_frame = fread(ftmp,Inf,"char")'; fclose(ftmp); + states.ntestframebits = length(test_frame); + printf("length test frame: %d\n", states.ntestframebits); + %test_frame = rand(1,states.ntestframebits) > 0.5; + + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + + tx = fsk_mod(states, tx_bits); + + %tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + printf("SNRdB meas: %4.1f\n", 10*log10(var(tx)/var(noise))); + + % dump simulated rx file + + ftx=fopen("fsk_horus.raw","wb"); rxg = rx*1000; fwrite(ftx, rxg, "short"); fclose(ftx); + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,nbit+states.ntestframebits); + x_log = []; + timing_nl_log = []; + norm_rx_timing_log = []; + f_int_resample_log = []; + f_log = []; + EbNodB_log = []; + rx_bits_log = []; + rx_bits_sd_log = []; + + % main loop --------------------------------------------------------------- + + run_frames = floor(length(rx)/N)-1; + for f=1:run_frames + + % extract nin samples from input stream + + nin = states.nin; + en = st + states.nin - 1; + + if en < length(rx) % due to nin variations its possible to overrun buffer + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + states = est_freq(states, sf, states.M); + states.f = 900 + 2*states.Rs*(1:states.M); + %states.f = [1200 1400 1600 1800]; + [rx_bits states] = fsk_demod(states, sf); + + rx_bits_buf(1:states.ntestframebits) = rx_bits_buf(nbit+1:states.ntestframebits+nbit); + rx_bits_buf(states.ntestframebits+1:states.ntestframebits+nbit) = rx_bits; + %rx_bits_buf(1:nbit) = rx_bits_buf(nbit+1:2*nbit); + %rx_bits_buf(nbit+1:2*nbit) = rx_bits; + + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + x_log = [x_log states.x]; + timing_nl_log = [timing_nl_log states.timing_nl]; + f_int_resample_log = [f_int_resample_log abs(states.f_int_resample(:,:))]; + f_log = [f_log; states.f]; + EbNodB_log = [EbNodB_log states.EbNodB]; + + if test_frame_mode == 1 + states = ber_counter(states, test_frame, rx_bits_buf); + end + if test_frame_mode == 6 + states = ber_counter_packet(states, test_frame, rx_bits_buf); + end + end + end + + % print stats, count errors, decode packets ------------------------------------------ + + if (test_frame_mode == 1) || (test_frame_mode == 6) + printf("frames: %d EbNo: %3.2f Tbits: %d Terrs: %d BER %4.3f\n", frames, EbNodB, states.Tbits,states. Terrs, states.Terrs/states.Tbits); + end + + if test_frame_mode == 4 + extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + end + + if test_frame_mode == 5 + extract_and_decode_binary_packets(states, rx_bits_log); + end + + figure(1); + plot(f_int_resample_log','+') + hold off; + + figure(2) + clf + m = max(abs(x_log)); + plot(x_log,'+') + axis([-m m -m m]) + title('fine timing metric') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log); + axis([1 run_frames -1 1]) + title('norm fine timing') + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(4) + clf + subplot(211) + one_sec_rx = rx(1:min(Fs,length(rx))); + plot(one_sec_rx) + title('rx signal at demod input') + subplot(212) + plot(abs(fft(one_sec_rx))) + + figure(5) + clf + plot(f_log,'+') + title('tone frequencies') + axis([1 run_frames 0 Fs/2]) + + figure(6) + clf + plot(EbNodB_log); + title('Eb/No estimate') + + figure(7) + clf + subplot(211) + X = abs(fft(timing_nl_log)); + plot(X(1:length(X)/2)) + subplot(212) + plot(abs(timing_nl_log(1:100))) + + endfunction + + +% demodulate a file of 8kHz 16bit short samples -------------------------------- + +function rx_bits_log = demod_file(filename, test_frame_mode, noplot=0, EbNodB=100) + fin = fopen(filename,"rb"); + more off; + + %states = fsk_horus_init(96000, 1200); + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100, 2); + uwstates = fsk_horus_init_rtty_uw(states); + states.ntestframebits = states.nbits; + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 50, 4); + uwstates = fsk_horus_init_binary_uw; + states.ntestframebits = states.nbits; + end + + states.verbose = 0x1 + 0x8; + + if test_frame_mode == 6 + % Horus high speed config -------------- + states = fsk_horus_init_hbr(9600, 8, 1200, 2, 16); + states.tx_bits_file = "horus_high_speed.bin"; + states.verbose += 0x4; + ftmp = fopen(states.tx_bits_file, "rb"); test_frame = fread(ftmp,Inf,"char")'; fclose(ftmp); + states.ntestframebits = length(test_frame); + printf("length test frame: %d\n", states.ntestframebits); + end + + if test_frame_mode == 7 + % 800XA 4FSK modem -------------- + states = fsk_horus_init_hbr(8000, 10, 400, 4, 256); + states.tx_bits_file = "horus_high_speed.bin"; + states.verbose += 0x4; + ftmp = fopen(states.tx_bits_file, "rb"); test_frame = fread(ftmp,Inf,"char")'; fclose(ftmp); + states.ntestframebits = length(test_frame); + printf("length test frame: %d\n", states.ntestframebits); + end + + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + nbit = states.nbit; + + frames = 0; + rx = []; + rx_bits_log = []; + rx_bits_sd_log = []; + norm_rx_timing_log = []; + f_int_resample_log = []; + EbNodB_log = []; + ppm_log = []; + f_log = []; + rx_bits_buf = zeros(1,nbit + states.ntestframebits); + + % optional noise. Useful for testing performance of waveforms from real world modulators + + EbNo = 10^(EbNodB/10); + ftmp = fopen(filename,"rb"); s = fread(ftmp,Inf,"short"); fclose(ftmp); tx_pwr = var(s); + variance = (tx_pwr/2)*states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % First extract raw bits from samples ------------------------------------------------------ + + printf("demod of raw bits....\n"); + + finished = 0; + while (finished == 0) + + % extract nin samples from input stream + + nin = states.nin; + [sf count] = fread(fin, nin, "short"); + rx = [rx; sf]; + + % add optional noise + + if count + noise = sqrt(variance)*randn(count,1); + sf += noise; + end + + if count == nin + frames++; + + % demodulate to stream of bits + + states = est_freq(states, sf, states.M); + %states.f = [1450 1590 1710 1850]; + [rx_bits states] = fsk_horus_demod(states, sf); + + rx_bits_buf(1:states.ntestframebits) = rx_bits_buf(nbit+1:states.ntestframebits+nbit); + rx_bits_buf(states.ntestframebits+1:states.ntestframebits+nbit) = rx_bits; + + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + f_int_resample_log = [f_int_resample_log abs(states.f_int_resample)]; + EbNodB_log = [EbNodB_log states.EbNodB]; + ppm_log = [ppm_log states.ppm]; + f_log = [f_log; states.f]; + + if test_frame_mode == 1 + states = ber_counter(states, test_frame, rx_bits_buf); + if states.ber_state == 1 + states.verbose = 0; + end + end + if test_frame_mode == 6 + states = ber_counter_packet(states, test_frame, rx_bits_buf); + end + else + finished = 1; + end + end + fclose(fin); + + if noplot == 0 + printf("plotting...\n"); + + figure(1); + plot(f_log); + hold off; + + figure(2); + plot(f_int_resample_log','+') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log) + axis([1 frames -0.5 0.5]) + title('norm fine timing') + grid + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(4) + clf + plot(EbNodB_log); + title('Eb/No estimate') + + figure(5) + clf + rx_nowave = rx(1000:length(rx)); + subplot(211) + plot(rx_nowave(1:states.Fs)); + title('input signal to demod (1 sec)') + xlabel('Time (samples)'); + axis([1 states.Fs -35000 35000]) + + % normalise spectrum to 0dB full scale with a 32767 sine wave input + + subplot(212) + RxdBFS = 20*log10(abs(fft(rx_nowave(1:states.Fs)))) - 20*log10((states.Fs/2)*32767); + plot(RxdBFS) + axis([1 states.Fs/2 -80 0]) + xlabel('Frequency (Hz)'); + + figure(6); + clf + plot(ppm_log) + title('Sample clock (baud rate) offset in PPM'); + end + + if (test_frame_mode == 1) || (test_frame_mode == 6) + printf("frames: %d Tbits: %d Terrs: %d BER %4.3f EbNo: %3.2f\n", frames, states.Tbits,states. Terrs, states.Terrs/states.Tbits, mean(EbNodB_log)); + end + + % we can decode both protocols at the same time + + if (test_frame_mode == 4) || (test_frame_mode == 5) + extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + corr_log = extract_and_decode_binary_packets(states, rx_bits_log); + + figure(8); + clf + plot(corr_log); + hold on; + plot([1 length(corr_log)],[states.binary.uw_thresh states.binary.uw_thresh],'g'); + hold off; + title('UW correlation'); + end + +endfunction + + +% run test functions from here during development + +if exist("fsk_horus_as_a_lib") == 0 + run_sim(1, 2, 100, 9); + %rx_bits = demod_file("~/Desktop/115.wav",6,0,90); + %rx_bits = demod_file("fsk_horus.raw",5); + %rx_bits = demod_file("~/Desktop/4FSK_Binary_NoLock.wav",4); + %rx_bits = demod_file("~/Desktop/phorus_binary_ascii.wav",4); + %rx_bits = demod_file("~/Desktop/binary/horus_160102_binary_rtty_2.wav",4); + %rx_bits = demod_file("~/Desktop/horus_160102_vk5ei_capture2.wav",4); + %rx_bits = demod_file("~/Desktop/horus_rtty_binary.wav",4); + %rx_bits = demod_file("~/Desktop/FSK_4FSK.wav",4); + %rx_bits = demod_file("t.raw",5); + %rx_bits = demod_file("~/Desktop/fsk_horus_10dB_1000ppm.wav",4); + %rx_bits = demod_file("~/Desktop/fsk_horus_6dB_0ppm.wav",4); + %rx_bits = demod_file("test.raw",1,1); + %rx_bits = demod_file("/dev/ttyACM0",1); + %rx_bits = demod_file("fsk_horus_rx_1200_96k.raw",1); + %rx_bits = demod_file("mp.raw",4); + %rx_bits = demod_file("~/Desktop/launchbox_v2_landing_8KHz_final.wav",4); + %rx_bits = demod_file("~/Desktop/bench_test_003.wav",7); +end diff --git a/codec2/branches/0.7/octave/fsk_horus_2fsk.m b/codec2/branches/0.7/octave/fsk_horus_2fsk.m new file mode 100644 index 00000000..4b92a00a --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_horus_2fsk.m @@ -0,0 +1,979 @@ +% fsk_horus.m +% David Rowe 10 Oct 2015 +% +% Experimental near space balloon FSK demodulator +% Assume high SNR, but fades near end of mission can wipe out a few bits +% So low SNR perf not a huge issue +% +% [X] processing buffers of 1 second +% + 8000 samples input +% + keep 30 second sliding window to extract packet from +% + do fine timing on this +% [X] estimate frequency of two tones +% + this way we cope with variable shift and drift +% + starts to lose it at 8 Eb/No = 8db. Maybe wider window? +% [X] estimate amplitudes and equalise, or limit +% + not needed - tones so close in freq unlikely to be significant ampl diff +% across SSB rx filter +% [X] Eb/No point 8dB, 2% ish +% [X] fine timing and sample slips, +/- 1000ppm (0.1%) clock offset test +% [ ] bit flipping against CRC +% [ ] implement CRC +% [X] frame sync +% [X] compare to fldigi +% + in AWGN channel 3-4dB improvement. In my tests fldigi can't decode +% with fading model, requires Eb/No > 40dB, this demo useable at Eb/No = 20dB +% [X] test over range of f1/f2, shifts, timing offsets, clock offsets, Eb/No +% [X] +/- 1000ppm clock offset OK at Eb/No = 10dB, starts to lose it at 8dB +% [X] tone freq est starts to lose it at 8dB in awgn. Maybe wider window? +% [ ] low snr detection of $$$$$$ +% + we might be able to pick up a "ping" at very low SNRs to help find baloon on ground +% [ ] streaming, indicator of audio freq, i.e. speaker output? + +% horus binary: +% [ ] BER estimate/found/corrected + +1; + +function states = fsk_horus_init(Fs,Rs) + states.Ndft = 2.^ceil(log2(Fs)); % find nearest power of 2 for effcient FFT + states.Fs = Fs; + N = states.N = Fs; % processing buffer size, nice big window for f1,f2 estimation + states.Rs = Rs; + Ts = states.Ts = Fs/Rs; + assert(Ts == floor(Ts), "Fs/Rs must be an integer"); + states.nsym = N/Ts; % number of symbols in one procesing frame + Nmem = states.Nmem = N+2*Ts; % two symbol memory in down converted signals to allow for timing adj + states.f1_dc = zeros(1,Nmem); + states.f2_dc = zeros(1,Nmem); + states.P = 8; % oversample rate out of filter + assert(Ts/states.P == floor(Ts/states.P), "Ts/P must be an integer"); + + states.nin = N; % can be N +/- Ts/P samples to adjust for sample clock offsets + states.verbose = 0; + states.phi1 = 0; % keep down converter osc phase continuous + states.phi2 = 0; + + printf("Fs: %d Rs: %d Ts: %d nsym: %d\n", states.Fs, states.Rs, states.Ts, states.nsym); + + % BER stats + + states.ber_state = 0; + states.Tbits = 0; + states.Terrs = 0; + states.nerr_log = 0; + + states.df = 0; + states.f1 = 0; + states.f2 = 0; + states.norm_rx_timing = 0; + states.ppm = 0; + states.prev_pkt = []; + + % protocol specific states + + states.rtty = fsk_horus_init_rtty_uw(states); + states.binary = fsk_horus_init_binary_uw; +endfunction + + +% init rtty protocol specifc states + +function rtty = fsk_horus_init_rtty_uw(states) + % Generate unque word that correlates against the ASCII "$$$$$" that + % is at the start of each frame. + + dollar_bits = fliplr([0 1 0 0 1 0 0]); + mapped_db = 2*dollar_bits - 1; + sync_bits = [1 1 0]; + mapped_sb = 2*sync_bits - 1; + %mapped_sb = [ 0 0 0 ]; + + mapped = [mapped_db mapped_sb]; + npad = rtty.npad = 3; % one start and two stop bits between 7 bit ascii chars + nfield = rtty.nfield = 7; % length of ascii character field + + rtty.uw = [mapped mapped mapped mapped mapped]; + + rtty.uw_thresh = length(rtty.uw) - 8; % allow a few bit errors when looking for UW + + rtty.max_packet_len = 1000; +endfunction + + + +function binary = fsk_horus_init_binary_uw + % Generate 16 bit "$$" unique word that is at the front of every horus binary + % packet + + dollar_bits = [0 0 1 0 0 1 0 0]; + mapped_db = 2*dollar_bits - 1; + + binary.uw = [mapped_db mapped_db]; + binary.uw_thresh = length(binary.uw); % no bit errors when looking for UW + + binary.max_packet_len = 400; +endfunction + + +% test modulator function + +function tx = fsk_horus_mod(states, tx_bits) + tx = zeros(states.Ts*length(tx_bits),1); + tx_phase = 0; + Ts = states.Ts; + Fs = states.Fs; + f1 = states.f1_tx; f2 = states.f2_tx; + df = states.df; % tone freq change in Hz/s + dA = states.dA; + + for i=1:length(tx_bits) + if tx_bits(i) == 0 + tx_phase_vec = tx_phase + (1:Ts)*2*pi*f1/Fs; + tx((i-1)*Ts+1:i*Ts) = dA*2.0*cos(tx_phase_vec); + else + tx_phase_vec = tx_phase + (1:Ts)*2*pi*f2/Fs; + tx((i-1)*Ts+1:i*Ts) = 2.0*cos(tx_phase_vec); + end + tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi; + f1 += df*Ts/Fs; f2 += df*Ts/Fs; + end +endfunction + + +% Given a buffer of nin input Rs baud FSK samples, returns nsym bits. +% +% Automagically estimates the frequency of the two tones, or +% looking at it another way, the frequency offset and shift +% +% nin is the number of input samples required by demodulator. This is +% time varying. It will nominally be N (8000), and occasionally N +/- +% Ts/2 (e.g. 8080 or 7920). This is how we compensate for differences between the +% remote tx sample clock and our sample clock. This function always returns +% N/Ts (50) demodulated bits. Variable number of input samples, constant number +% of output bits. + +function [rx_bits states] = fsk_horus_demod(states, sf) + N = states.N; + Ndft = states.Ndft; + Fs = states.Fs; + Rs = states.Rs; + Ts = states.Ts; + nsym = states.nsym; + P = states.P; + nin = states.nin; + verbose = states.verbose; + Nmem = states.Nmem; + + assert(length(sf) == nin); + + % find tone frequency and amplitudes --------------------------------------------- + + h = hanning(nin); + Sf = fft(sf .* h, Ndft); + [m1 m1_index] = max(Sf(1:Ndft/2)); + + % zero out region 100Hz either side of max so we can find second highest peak + + Sf2 = Sf; + st = m1_index - floor(100*Ndft/Fs); + if st < 1 + st = 1; + end + en = m1_index + floor(100*Ndft/Fs); + if en > Ndft/2 + en = Ndft/2; + end + Sf2(st:en) = 0; + + [m2 m2_index] = max(Sf2(1:Ndft/2)); + + % f1 always the lower tone + + if m1_index < m2_index + f1 = (m1_index-1)*Fs/Ndft; + f2 = (m2_index-1)*Fs/Ndft; + twist = 20*log10(m1/m2); + else + f1 = (m2_index-1)*Fs/Ndft; + f2 = (m1_index-1)*Fs/Ndft; + twist = 20*log10(m2/m1); + end + + states.f1 = f1; + states.f2 = f2; + + if bitand(verbose,0x1) + printf("centre: %4.0f shift: %4.0f twist: %3.1f dB\n", (f2+f1)/2, f2-f1, twist); + end + if bitand(verbose,0x8) + printf("f1: %4.0f Hz f2: %4.0f Hz a1: %f a2: %f\n", f1, f2, 2.0*abs(m1)/Ndft, 2.0*abs(m2)/Ndft); + end + + % down convert and filter at rate P ------------------------------ + + % update filter (integrator) memory by shifting in nin samples + + nold = Nmem-nin; % number of old samples we retain + + f1_dc = states.f1_dc; + f1_dc(1:nold) = f1_dc(Nmem-nold+1:Nmem); + f2_dc = states.f2_dc; + f2_dc(1:nold) = f2_dc(Nmem-nold+1:Nmem); + + % shift down to around DC, ensuring continuous phase from last frame + + phi1_vec = states.phi1 + (1:nin)*2*pi*f1/Fs; + phi2_vec = states.phi2 + (1:nin)*2*pi*f2/Fs; + + f1_dc(nold+1:Nmem) = sf' .* exp(-j*phi1_vec); + f2_dc(nold+1:Nmem) = sf' .* exp(-j*phi2_vec); + + states.phi1 = phi1_vec(nin); + states.phi1 -= 2*pi*floor(states.phi1/(2*pi)); + states.phi2 = phi2_vec(nin); + states.phi2 -= 2*pi*floor(states.phi2/(2*pi)); + + % save filter (integrator) memory for next time + + states.f1_dc = f1_dc; + states.f2_dc = f2_dc; + + % integrate over symbol period, which is effectively a LPF, removing + % the -2Fc frequency image. Can also be interpreted as an ideal + % integrate and dump, non-coherent demod. We run the integrator at + % rate P (1/P symbol offsets) to get outputs at a range of different + % fine timing offsets. We calculate integrator output over nsym+1 + % symbols so we have extra samples for the fine timing re-sampler at either + % end of the array. + + rx_bits = zeros(1, (nsym+1)*P); + for i=1:(nsym+1)*P + st = 1 + (i-1)*Ts/P; + en = st+Ts-1; + f1_int(i) = sum(f1_dc(st:en)); + f2_int(i) = sum(f2_dc(st:en)); + end + states.f1_int = f1_int; + states.f2_int = f2_int; + + % fine timing estimation ----------------------------------------------- + + % Non linearity has a spectral line at Rs, with a phase + % related to the fine timing offset. See: + % http://www.rowetel.com/blog/?p=3573 + % We have sampled the integrator output at Fs=P samples/symbol, so + % lets do a single point DFT at w = 2*pi*f/Fs = 2*pi*Rs/(P*Rs) + + Np = length(f1_int); + w = 2*pi*(Rs)/(P*Rs); + x = ((abs(f1_int)-abs(f2_int)).^2) * exp(-j*w*(0:Np-1))'; + norm_rx_timing = angle(x)/(2*pi); + rx_timing = norm_rx_timing*P; + + states.x = x; + states.rx_timing = rx_timing; + prev_norm_rx_timing = states.norm_rx_timing; + states.norm_rx_timing = norm_rx_timing; + + % estimate sample clock offset in ppm + % d_norm_timing is fraction of symbol period shift over nsym symbols + + d_norm_rx_timing = norm_rx_timing - prev_norm_rx_timing; + + % filter out big jumps due to nin changes + + if abs(d_norm_rx_timing) < 0.2 + appm = 1E6*d_norm_rx_timing/nsym; + states.ppm = 0.9*states.ppm + 0.1*appm; + end + + % work out how many input samples we need on the next call. The aim + % is to keep angle(x) away from the -pi/pi (+/- 0.5 fine timing + % offset) discontinuity. The side effect is to track sample clock + % offsets + + next_nin = N; + if norm_rx_timing > 0.25 + next_nin += Ts/2; + end + if norm_rx_timing < -0.25; + next_nin -= Ts/2; + end + states.nin = next_nin; + + % Re-sample integrator outputs using fine timing estimate and linear interpolation + + low_sample = floor(rx_timing); + fract = rx_timing - low_sample; + high_sample = ceil(rx_timing); + + if bitand(verbose,0x2) + printf("rx_timing: %3.2f low_sample: %d high_sample: %d fract: %3.3f nin_next: %d\n", rx_timing, low_sample, high_sample, fract, next_nin); + end + + f1_int_resample = zeros(1,nsym); + f2_int_resample = zeros(1,nsym); + rx_bits = zeros(1,nsym); + rx_bits_sd = zeros(1,nsym); + for i=1:nsym + st = i*P+1; + f1_int_resample(i) = f1_int(st+low_sample)*(1-fract) + f1_int(st+high_sample)*fract; + f2_int_resample(i) = f2_int(st+low_sample)*(1-fract) + f2_int(st+high_sample)*fract; + %f1_int_resample(i) = f1_int(st+1); + %f2_int_resample(i) = f2_int(st+1); + rx_bits(i) = abs(f2_int_resample(i)) > abs(f1_int_resample(i)); + rx_bits_sd(i) = abs(f2_int_resample(i)) - abs(f1_int_resample(i)); + end + + states.f1_int_resample = f1_int_resample; + states.f2_int_resample = f2_int_resample; + states.rx_bits_sd = rx_bits_sd; + + % Eb/No estimation + + x = abs(abs(f1_int_resample) - abs(f2_int_resample)); + states.EbNodB = 20*log10(1E-6+mean(x)/(1E-6+std(x))); +endfunction + + +% Look for unique word and return index of first UW bit, or -1 if no +% UW found Sometimes there may be several matches, returns the +% position of the best match to UW. + +function uw_start = find_uw(states, start_bit, rx_bits) + uw = states.uw; + + mapped_rx_bits = 2*rx_bits - 1; + best_corr = 0; + uw_start = -1; + + for i=start_bit:length(rx_bits) - length(uw) + corr = mapped_rx_bits(i:i+length(uw)-1) * uw'; + if (corr >= states.uw_thresh) && (corr > best_corr) + uw_start = i; + best_corr = corr; + end + end +endfunction + + +% Extract ASCII string from a Horus frame of bits + +function [str crc_ok] = extract_ascii(states, rx_bits_buf, uw_loc) + nfield = states.nfield; + npad = states.npad; + + str = []; str_dec = []; nstr = 0; ptx_crc = 1; rx_crc = ""; + endpacket = 0; + + st = uw_loc + length(states.uw); % first bit of first char + en = uw_loc + states.max_packet_len - nfield; + %printf("\nst: %d en: %d len: %d\n", st, en, length(rx_bits_buf)); + + for i=st:nfield+npad:en + field = rx_bits_buf(i:i+nfield-1); + ch_dec = field * (2.^(0:nfield-1))'; + + % filter out unlikely characters that bit errors may introduce, and ignore \n + + if (ch_dec > 31) && (ch_dec < 91) + str = [str char(ch_dec)]; + else + str = [str char(32)]; % space is "not sure" + end + nstr++; + + % build up array for CRC16 check + + if !endpacket && (ch_dec == 42) + endpacket = 1; + rx_crc = crc16(str_dec); % found a '*' so that's the end of the string for CRC calculations + ptx_crc = nstr+1; % this is where the transmit CRC starts + end + if !endpacket + str_dec = [str_dec ch_dec]; + end + end + + if (ptx_crc+3) <= length(str) + tx_crc = str(ptx_crc:ptx_crc+3); + crc_ok = strcmp(tx_crc, rx_crc); + else + crc_ok = 0; + end + + str = str(1:ptx_crc-2); + +endfunction + + +% Use soft decision information to find bits most likely in error. I think +% this is some form of maximum likelihood decoding. + +function [str crc_ok rx_bits_log_flipped] = sd_bit_flipping(states, rx_bits_log, rx_bits_sd_log, st, en); + + % force algorithm to ignore rs232 sync bits by marking them as "very likely", they have + % no input to crc algorithm + + nfield = states.nfield; + npad = states.npad; + for i=st:nfield+npad:en + rx_bits_sd_log(i+nfield:i+nfield+npad-1) = 1E6; + end + + % make a list of bits with smallest soft decn values + + [dodgy_bits_mag dodgy_bits_index] = sort(abs(rx_bits_sd_log(st+length(states.uw):en))); + dodgy_bits_index += length(states.uw) + st - 1; + nbits = 6; + ntries = 2^nbits; + str = ""; + crc_ok = 0; + + % try various combinations of these bits + + for i=1:ntries-1 + error_mask = zeros(1, length(rx_bits_log)); + for b=1:nbits + x = bitget(i,b); + bit_to_flip = dodgy_bits_index(b); + error_mask(bit_to_flip) = x; + %printf("st: %d i: %d b: %d x: %d index: %d\n", st, i,b,x,bit_to_flip); + end + rx_bits_log_flipped = xor(rx_bits_log, error_mask); + [str_flipped crc_ok_flipped] = extract_ascii(states, rx_bits_log_flipped, st); + if crc_ok_flipped + %printf("Yayy we fixed a packet by flipping with pattern %d\n", i); + str = str_flipped; + crc_ok = crc_ok_flipped; + end + end +endfunction + + +% Extract as many ASCII packets as we can from a great big buffer of bits + +function extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + + % use UWs to delimit start and end of data packets + + bit = 1; + nbits = length(rx_bits_log); + nfield = states.rtty.nfield; + npad = states.rtty.npad; + + uw_loc = find_uw(states.rtty, bit, rx_bits_log); + + while (uw_loc != -1) + + if (uw_loc + states.rtty.max_packet_len) < nbits + % Now start picking out 7 bit ascii chars from frame. It has some + % structure so we can guess where fields are. I hope we don't get + % RS232 idle bits stuck into it anywhere, ie "bit fields" don't + % change dynamically. + + % dump msg bits so we can use them as a test signal + %msg = rx_bits_log(st:uw_loc-1); + %save -ascii horus_msg.txt msg + + % simulate bit error for testing + %rx_bits_log(st+200) = xor(rx_bits_log(st+100),1); + %rx_bits_sd_log(st+100) = 0; + + [str crc_ok] = extract_ascii(states.rtty, rx_bits_log, uw_loc); + + if crc_ok == 0 + [str_flipped crc_flipped_ok rx_bits_log] = sd_bit_flipping(states.rtty, rx_bits_log, rx_bits_sd_log, uw_loc, uw_loc+states.rtty.max_packet_len); + if crc_flipped_ok + str = sprintf("%s fixed", str_flipped); + end + end + + % update memory of previous packet, we use this to guess where errors may be + if crc_ok || crc_flipped_ok + states.prev_pkt = rx_bits_log(uw_loc+length(states.rtty.uw):uw_loc+states.rtty.max_packet_len); + end + if crc_ok + str = sprintf("%s CRC OK", str); + else + str = sprintf("%s CRC BAD", str); + end + printf("%s\n", str); + end + + % look for next packet + + bit = uw_loc + length(states.rtty.uw); + uw_loc = find_uw(states.rtty, bit, rx_bits_log); + + endwhile +endfunction + + +% Extract as many ASCII packets as we can from a great big buffer of bits, +% and send them to the C decoder for FEC decoding. +% horus_l2 can be compiled a bunch of different ways. You need to +% compile with: +% codec2-dev/src$ gcc horus_l2.c -o horus_l2 -Wall -DDEC_RX_BITS -DHORUS_L2_RX + +function extract_and_decode_binary_packets(states, rx_bits_log) + + % use UWs to delimit start and end of data packets + + bit = 1; + nbits = length(rx_bits_log); + + uw_loc = find_uw(states.binary, bit, rx_bits_log); + + while (uw_loc != -1) + + if (uw_loc+states.binary.max_packet_len) < nbits + %printf("st: %d uw_loc: %d\n", st, uw_loc); + + % OK we have a packet delimited by two UWs. Lets convert the bit + % stream into bytes and save for decoding + + pin = uw_loc; + for i=1:45 + rx_bytes(i) = rx_bits_log(pin:pin+7) * (2.^(7:-1:0))'; + pin += 8; + %printf("%d 0x%02x\n", i, rx_bytes(i)); + end + + f=fopen("horus_rx_bits_binary.txt","wt"); + fwrite(f, rx_bytes, "uchar"); + fclose(f); + + system("../src/horus_l2"); % compile instructions above + end + + bit = uw_loc + length(states.binary.uw); + uw_loc = find_uw(states.binary, bit, rx_bits_log); + + endwhile +endfunction + + +% BER counter and test frame sync logic + +function states = ber_counter(states, test_frame, rx_bits_buf) + nsym = states.nsym; + state = states.ber_state; + next_state = state; + + if state == 0 + + % try to sync up with test frame + + nerrs_min = nsym; + for i=1:nsym + error_positions = xor(rx_bits_buf(i:nsym+i-1), test_frame); + nerrs = sum(error_positions); + if nerrs < nerrs_min + nerrs_min = nerrs; + states.coarse_offset = i; + end + end + if nerrs_min/nsym < 0.05 + next_state = 1; + end + if bitand(states.verbose,0x4) + printf("coarse offset: %d nerrs_min: %d next_state: %d\n", states.coarse_offset, nerrs_min, next_state); + end + end + + if state == 1 + + % we're synced up, lets measure bit errors + + error_positions = xor(rx_bits_buf(states.coarse_offset:states.coarse_offset+nsym-1), test_frame); + nerrs = sum(error_positions); + if nerrs/nsym > 0.1 + next_state = 0; + else + states.Terrs += nerrs; + states.Tbits += nsym; + states.nerr_log = [states.nerr_log nerrs]; + end + end + + states.ber_state = next_state; +endfunction + + +% simulation of tx and rx side, add noise, channel impairments ---------------------- + +function run_sim(test_frame_mode) + frames = 60; + EbNodB = 10; + timing_offset = 0.0; % see resample() for clock offset below + fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + df = 0; % tx tone freq drift in Hz/s + dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',1); + randn('state',1); + + % ---------------------------------------------------------------------- + + % sm2000 config ------------------------ + %states = fsk_horus_init(96000, 1200); + %states.f1_tx = 4000; + %states.f2_tx = 5200; + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100); + states.f1_tx = 1200; + states.f2_tx = 1600; + states.tx_bits_file = "horus_tx_bits_rtty.txt"; % Octave file of bits we FSK modulate + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 100); + states.f1_tx = 1200; + states.f2_tx = 1600; + states.tx_bits_file = "horus_tx_bits_binary.txt"; % Octave file of bits we FSK modulate + end + + % ---------------------------------------------------------------------- + + states.verbose = 0x1; + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + Fs = states.Fs; + states.df = df; + states.dA = dA; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nsym)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nsym*(frames+1))); + end + if test_frame_mode == 3 + % ...10101... sequence + tx_bits = zeros(1, states.nsym*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + end + + if (test_frame_mode == 4) || (test_frame_mode == 5) + + % load up a horus msg from disk and modulate that + + test_frame = load(states.tx_bits_file); + ltf = length(test_frame); + ntest_frames = ceil((frames+1)*nsym/ltf); + tx_bits = []; + for i=1:ntest_frames + tx_bits = [tx_bits test_frame]; + end + end + + tx = fsk_horus_mod(states, tx_bits); + + %tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + %rx = real(rx); + %b1 = fir2(100, [0 4000 5200 48000]/48000, [1 1 0.5 0.5]); + %rx = filter(b1,1,rx); + %[b a] = cheby2(6,40,[3000 6000]/(Fs/2)); + %rx = filter(b,a,rx); + %rx = sign(rx); + %rx(find (rx > 1)) = 1; + %rx(find (rx < -1)) = -1; + + % dump simulated rx file + ftx=fopen("fsk_horus_100bd_binary.raw","wb"); rxg = rx*1000; fwrite(ftx, rxg, "short"); fclose(ftx); + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,2*nsym); + x_log = []; + norm_rx_timing_log = []; + f1_int_resample_log = []; + f2_int_resample_log = []; + f1_log = f2_log = []; + EbNodB_log = []; + rx_bits_log = []; + rx_bits_sd_log = []; + + for f=1:frames + + % extract nin samples from input stream + + nin = states.nin; + en = st + states.nin - 1; + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + [rx_bits states] = fsk_horus_demod(states, sf); + rx_bits_buf(1:nsym) = rx_bits_buf(nsym+1:2*nsym); + rx_bits_buf(nsym+1:2*nsym) = rx_bits; + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + x_log = [x_log states.x]; + f1_int_resample_log = [f1_int_resample_log abs(states.f1_int_resample)]; + f2_int_resample_log = [f2_int_resample_log abs(states.f2_int_resample)]; + f1_log = [f1_log states.f1]; + f2_log = [f2_log states.f2]; + EbNodB_log = [EbNodB_log states.EbNodB]; + + if test_frame_mode == 1 + states = ber_counter(states, test_frame, rx_bits_buf); + end + end + + if test_frame_mode == 1 + printf("frames: %d Tbits: %d Terrs: %d BER %4.3f\n", frames, states.Tbits,states. Terrs, states.Terrs/states.Tbits); + end + + if test_frame_mode == 4 + extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + end + + if test_frame_mode == 5 + extract_and_decode_binary_packets(states, rx_bits_log); + end + + figure(1); + plot(f1_int_resample_log,'+') + hold on; + plot(f2_int_resample_log,'g+') + hold off; + + figure(2) + clf + m = max(abs(x_log)); + plot(x_log,'+') + axis([-m m -m m]) + title('fine timing metric') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log); + axis([1 frames -1 1]) + title('norm fine timing') + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(4) + clf + subplot(211) + plot(real(rx(1:Fs))) + title('rx signal at demod input') + subplot(212) + plot(abs(fft(rx(1:Fs)))) + + figure(5) + clf + plot(f1_log) + hold on; + plot(f2_log,'g'); + hold off; + title('tone frequencies') + axis([1 frames 0 Fs/2]) + + figure(6) + clf + plot(EbNodB_log); + title('Eb/No estimate') + +endfunction + + +% demodulate a file of 8kHz 16bit short samples -------------------------------- + +function rx_bits_log = demod_file(filename, test_frame_mode, noplot) + fin = fopen(filename,"rb"); + more off; + + %states = fsk_horus_init(96000, 1200); + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100); + uwstates = fsk_horus_init_rtty_uw(states); + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 100); + uwstates = fsk_horus_init_binary_uw; + end + + states.verbose = 0x1 + 0x8; + + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + rand('state',1); + test_frame = round(rand(1, states.nsym)); + + frames = 0; + rx = []; + rx_bits_log = []; + rx_bits_sd_log = []; + norm_rx_timing_log = []; + f1_int_resample_log = []; + f2_int_resample_log = []; + EbNodB_log = []; + ppm_log = []; + rx_bits_buf = zeros(1,2*nsym); + + % First extract raw bits from samples ------------------------------------------------------ + + printf("demod of raw bits....\n"); + + finished = 0; + while (finished == 0) + + % hit any key to finish (useful for real time streaming) + + %x = kbhit(1); + %if length(x) + % finished = 1; + %end + + % extract nin samples from input stream + + nin = states.nin; + [sf count] = fread(fin, nin, "short"); + rx = [rx; sf]; + + if count == nin + frames++; + + % demodulate to stream of bits + + [rx_bits states] = fsk_horus_demod(states, sf); + rx_bits_buf(1:nsym) = rx_bits_buf(nsym+1:2*nsym); + rx_bits_buf(nsym+1:2*nsym) = rx_bits; % xor(rx_bits,ones(1,nsym)); + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + f1_int_resample_log = [f1_int_resample_log abs(states.f1_int_resample)]; + f2_int_resample_log = [f2_int_resample_log abs(states.f2_int_resample)]; + EbNodB_log = [EbNodB_log states.EbNodB]; + ppm_log = [ppm_log states.ppm]; + + if test_frame_mode == 1 + states = ber_counter(states, test_frame, rx_bits_buf); + if states.ber_state == 1 + states.verbose = 0; + end + end + else + finished = 1; + end + end + fclose(fin); + + if exist("noplot") == 0 + printf("plotting...\n"); + + figure(1); + plot(f1_int_resample_log,'+') + hold on; + plot(f2_int_resample_log,'g+') + hold off; + + figure(2) + clf + subplot(211) + plot(norm_rx_timing_log) + axis([1 frames -0.5 0.5]) + title('norm fine timing') + grid + subplot(212) + plot(states.nerr_log) + title('num bit errors each frame') + + figure(3) + clf + plot(EbNodB_log); + title('Eb/No estimate') + + figure(4) + clf + subplot(211) + plot(rx(1:states.Fs)); + title('input signal to demod (1 sec)') + xlabel('Time (samples)'); + axis([1 states.Fs -35000 35000]) + + % normalise spectrum to 0dB full scale witha 32767 sine wave input + + subplot(212) + RxdBFS = 20*log10(abs(fft(rx(1:states.Fs)))) - 20*log10((states.Fs/2)*32767); + plot(RxdBFS) + axis([1 states.Fs/2 -80 0]) + xlabel('Frequency (Hz)'); + + figure(5); + clf + plot(ppm_log) + title('Sample clock (baud rate) offset in PPM'); + end + + if test_frame_mode == 1 + printf("frames: %d Tbits: %d Terrs: %d BER %4.3f EbNo: %3.2f\n", frames, states.Tbits,states. Terrs, states.Terrs/states.Tbits, mean(EbNodB_log)); + end + + % we can decode both protocols at the same time + + if (test_frame_mode == 4) || (test_frame_mode == 5) + extract_and_print_rtty_packets(states, rx_bits_log, rx_bits_sd_log) + extract_and_decode_binary_packets(states, rx_bits_log); + end +endfunction + + +% run test functions from here during development + +if exist("fsk_horus_as_a_lib") == 0 + %run_sim(5); + %rx_bits = demod_file("horus.raw",4); + %rx_bits = demod_file("fsk_horus_100bd_binary.raw",5); + rx_bits = demod_file("~/Desktop/phorus_binary_ascii.wav",4); + %rx_bits = demod_file("~/Desktop/horus_rtty_binary.wav",4); + %rx_bits = demod_file("t.raw",5); + %rx_bits = demod_file("~/Desktop/fsk_horus_10dB_1000ppm.wav",4); + %rx_bits = demod_file("~/Desktop/fsk_horus_6dB_0ppm.wav",4); + %rx_bits = demod_file("test.raw",1,1); + %rx_bits = demod_file("/dev/ttyACM0",1); + %rx_bits = demod_file("fsk_horus_rx_1200_96k.raw",1); + %rx_bits = demod_file("mp.raw",4); + %rx_bits = demod_file("~/Desktop/launchbox_v2_landing_8KHz_final.wav",4); +end diff --git a/codec2/branches/0.7/octave/fsk_horus_stream.m b/codec2/branches/0.7/octave/fsk_horus_stream.m new file mode 100755 index 00000000..4158104f --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_horus_stream.m @@ -0,0 +1,227 @@ +#!/usr/bin/octave -qf + +% fsk_horus_stream.m +% David Rowe 13 Oct 2015 +% +% Experimental real time near space balloon FSK demodulator, takes +% 8kHz 16 bit samples from stdin, output txt string on stdout +% +% usage: +% +% $ chmod 777 fsk_horus_stream.m +% $ rec -t raw -r 8000 -s -2 -c 1 - -q | ./fsk_horus_stream.m 2 100 +% +% Or with pulseaudio you can decode two different waveforms at the +% same time. In two different shells start: +% +% $ arecord -D pulse -r 8000 -c 1 -f S16_LE - | ./fsk_horus_stream.m 2 100 +% $ arecord -D pulse -r 8000 -c 1 -f S16_LE - | ./fsk_horus_stream.m 4 50 +% +% 'pavucontrol' utility can be used to select a sound device for arecord. +% +% To test with a stored file (8kHz 16-bit shorts): +% +% $ cat ~/Desktop/vk5arg-3.wav | ./fsk_horus_stream.m 2 100 +% + +% command line arguments + +arg_list = argv (); +if nargin == 0 + printf("\nusage: %s [mFSKtones] [SymbolRateHz]\n\n", program_name()); + printf("Horus RTTY 2FSK 100 baud:\n\n"); + printf(" %s 2 100\n\n", program_name()); + printf("Horus Binary 4FSK 50 baud\n\n"); + printf(" %s 4 50\n\n", program_name()); + exit(0); +end + +mFSK = str2num(arg_list{1}); +Rs = str2num(arg_list{2}); +telem_upload_enabled = false; +if nargin == 3 + % Optionally upload Telemetry to Habitat (http://tracker.habhub.org/) + if strcmp(arg_list{3}, "telem") + telem_upload_enabled = true; + end +end +printf ("\nmFSK: %d Rs: %d nargin: %d telem: %d\n", mFSK, Rs, nargin, telem_upload_enabled); + +% include modem library + +fsk_horus_as_a_lib = 1; % make sure calls to test functions at bottom are disabled +fsk_horus; + +gps_log = "~/Desktop/gps_log.txt" +system_command = "echo -n \"/home/david/Desktop/gps_log.txt\" | nc -u -q1 127.0.0.1 21234"; + +% Update this command with your own callsign. +telem_upload_command = "python telem_upload.py -c vk5dgr_Octave"; + +more off; +states = fsk_horus_init(8000, Rs, mFSK); +uwstates = fsk_horus_init_rtty_uw(states); +N = states.N; +Rs = states.Rs; +nsym = states.nsym; +nin = states.nin; +nfield = states.rtty.nfield; +npad = states.rtty.npad; +EbNo = 0; +SNR = 0; + +rx = []; +rx_bits_buf = []; +rx_bits_sd_buf = []; + +[s,c] = fread(stdin, N, "short"); + +while c + + rx = [rx s']; + + % demodulate samples to bit stream + + while length(rx) > nin + states = est_freq(states, rx(1:nin)', states.M); + [rx_bits states] = fsk_horus_demod(states, rx(1:nin)'); + rx_bits_buf = [rx_bits_buf rx_bits]; + rx_bits_sd_buf = [rx_bits_sd_buf states.rx_bits_sd]; + rx = rx(nin+1:length(rx)); + nin = states.nin; + EbNo = 0.9*EbNo + 0.1*states.EbNodB; + SNR = EbNo + 10*log10(states.Rs/3000); + %printf("nin: %d length(rx): %d length(rx_bits_buf): %d \n", nin, length(rx), length(rx_bits_buf)); + endwhile + f = states.f(1); + printf("max: %d f1: %d ppm: %d Eb/No: %3.1f SNR: %3.1f bits: %d\r", max(s), f, states.ppm, EbNo, SNR, length(rx_bits_buf)); + + packet_found = 0; + + % Look for complete Horus RTTY frame ------------------------------------------------------------------- + + nbits = length(rx_bits_buf); + uw_loc = find_uw(states.rtty, 1, rx_bits_buf); + + if uw_loc != -1 + packet_found = 1; + + if (uw_loc + states.rtty.max_packet_len) < nbits + %printf("\n%d nbits: %d\n",uw_loc + states.rtty.max_packet_len, nbits); + + [str crc_ok] = extract_ascii(states.rtty, rx_bits_buf, uw_loc); + + if crc_ok == 0 + [str_flipped crc_flipped_ok] = sd_bit_flipping(states.rtty, rx_bits_buf, rx_bits_sd_buf, uw_loc, uw_loc+states.rtty.max_packet_len); + if crc_flipped_ok + str = sprintf("%s fixed", str_flipped); + crc_ok = 1; + end + end + + if crc_ok + if telem_upload_enabled + % Upload to Habitat. + ascii_upload_cmd = sprintf("%s %s",telem_upload_command,str); + printf("Uploading ASCII to Habitat...\n"); + system(ascii_upload_cmd,false,"async"); + end + + strok = sprintf("%s CRC OK", str); + else + strok = sprintf("%s CRC BAD", str); + end + printf("\n %s \n", strok); + + % throw out used bits in buffer. We're not sure where the next packet starts + % so lets remove everything up to just after the UW we just used to force + % a search for the next UW. + + rx_bits_buf = rx_bits_buf(uw_loc+length(states.rtty.uw):length(rx_bits_buf)); + rx_bits_sd_buf = rx_bits_sd_buf(uw_loc+length(states.rtty.uw):length(rx_bits_sd_buf)); + + if crc_ok + % extract GPS coords and save to log file for mapping software + + str_split = strsplit(str,","); + if length(str_split) > 4 + lat = str_split{1,4}; long = str_split{1,5}; + f = fopen(gps_log,"at"); + fprintf(f,"%s,%s\n", lat, long); + fclose(f); + end + + % TODO: thin out log file to max_points to lighten plotting load + + % tell foxtrotGPS to plot track + + system(system_command); + end + end + end + + % Look for complete Horus BINARY frame ------------------------------------------------------------------- + + nbits = length(rx_bits_buf); + uw_loc = find_uw(states.binary, 1, rx_bits_buf); + + if uw_loc != -1 + packet_found = 1; + + if (uw_loc + states.binary.max_packet_len) < nbits + + pin = uw_loc; + nbytes = states.binary.max_packet_len/8; + for i=1:nbytes + if (pin+7) > nbits + pin + nbits + uw_loc + states.binary.max_packet_len + end + rx_bytes(i) = rx_bits_buf(pin:pin+7) * (2.^(7:-1:0))'; + pin += 8; + %printf("%d 0x%02x\n", i, rx_bytes(i)); + end + + printf("\n "); + f=fopen("horus_rx_bits_binary.bin","wt"); + fwrite(f, rx_bytes, "uchar"); + fclose(f); + + % horus_l2 can be compiled a bunch of different ways. You need to + % compile with: + % codec2-dev/src$ gcc horus_l2.c -o horus_l2 -Wall -DDEC_RX_BITS -DHORUS_L2_RX + + system("../src/horus_l2"); + if telem_upload_enabled + % Upload binary payload data to Habitat. + binary_upload_addition = "`cat horus_rx_bits_hex.txt`"; + binary_upload_cmd = sprintf("%s %s",telem_upload_command,binary_upload_addition); + printf("Uploading Binary to Habitat...\n"); + system(binary_upload_cmd,type="async"); + end + + % throw out used bits in buffer. We're not sure where the next packet starts + % so lets remove everything up to just after the UW we just used to force + % a search for the next UW. + + rx_bits_buf = rx_bits_buf(uw_loc+length(states.binary.uw):length(rx_bits_buf)); + rx_bits_sd_buf = rx_bits_sd_buf(uw_loc+length(states.binary.uw):length(rx_bits_sd_buf)); + end + end + + % Truncate buffers if no UW found so they don't grow endlessly with no signal. + % Keep very end of it as it may have part of a UW in it + + if packet_found == 0 + max_len = states.rtty.max_packet_len*4; + if length(rx_bits_buf) > max_len + rx_bits_buf = rx_bits_buf(length(rx_bits_buf)-states.rtty.max_packet_len:length(rx_bits_buf)); + rx_bits_sd_buf = rx_bits_sd_buf(length(rx_bits_sd_buf)-states.rtty.max_packet_len:length(rx_bits_sd_buf)); + end + end + + [s,c] = fread(stdin, N, "short"); + +endwhile diff --git a/codec2/branches/0.7/octave/fsk_lib.m b/codec2/branches/0.7/octave/fsk_lib.m new file mode 100644 index 00000000..87252428 --- /dev/null +++ b/codec2/branches/0.7/octave/fsk_lib.m @@ -0,0 +1,476 @@ +% fsk_lib.m +% David Rowe Oct 2015 - present +% +% mFSK modem, started out life as RTTY demodulator for Project +% Horus High Altitude Ballon (HAB) telemetry, also used for: +% +% FreeDV 2400A: 4FSK UHF/UHF digital voice +% Wenet.......: 100 kbit/s HAB High Def image telemetry +% +% Handles frequency offsets, performance right on ideal, C implementation +% in codec2-dev/src + +% NOTE: DR is in the process of refactoring this Octave code, pls email me +% if something is broken + +1; + +function states = fsk_init(Fs, Rs, M=2) + states.M = M; + states.bitspersymbol = log2(M); + states.Fs = Fs; + states.Rs = Rs; + + states.nsym = 50; % need enough symbols for good timing and freq offset est + Ts = states.Ts = Fs/Rs; % number of samples per symbol + assert(Ts == floor(Ts), "Fs/Rs must be an integer"); + + N = states.N = Ts*states.nsym; % processing buffer size, nice big window for timing est + states.Ndft = min(1024, 2.^ceil(log2(N))); % find nearest power of 2 for efficient FFT + states.nbit = states.nsym*states.bitspersymbol; % number of bits per processing frame + + Nmem = states.Nmem = N+2*Ts; % two symbol memory in down converted signals to allow for timing adj + + states.Sf = zeros(states.Ndft/2,1); % current memory of dft mag samples + states.f_dc = zeros(M,Nmem); + states.P = 8; % oversample rate out of filter + assert(Ts/states.P == floor(Ts/states.P), "Ts/P must be an integer"); + + states.nin = N; % can be N +/- Ts/P samples to adjust for sample clock offsets + states.verbose = 0; + states.phi = zeros(1, M); % keep down converter osc phase continuous + + %printf("M: %d Fs: %d Rs: %d Ts: %d nsym: %d nbit: %d\n", states.M, states.Fs, states.Rs, states.Ts, states.nsym, states.nbit); + + % BER stats + + states.ber_state = 0; + states.Tbits = 0; + states.Terrs = 0; + states.nerr_log = 0; + + % extra simulation parameters + + states.tx_real = 1; + states.dA(1:M) = 1; + states.df(1:M) = 0; + states.f(1:M) = 0; + states.norm_rx_timing = 0; + states.ppm = 0; + states.prev_pkt = []; + + % Freq. estimator limits - keep these narrow to stop errors with low SNR 4FSK + % todo: make this Fs indep + + states.fest_fmin = 800; + states.fest_fmax = 2500; + states.fest_min_spacing = 200; +endfunction + + +% Alternative init function, useful for high speed (non telemetry) modems +% Allows fine grained control of decimation P +% Small, processing window nsym rather than nsym=Fs (1 second window) +% Wider freq est limits + +function states = fsk_init_hbr(Fs,P,Rs,M=2,nsym=48) + + states.M = M; + states.bitspersymbol = log2(M); + states.Fs = Fs; + states.Rs = Rs; + Ts = states.Ts = Fs/Rs; + assert(Ts == floor(Ts), "Fs/Rs must be an integer"); + N = states.N = Ts*nsym; % processing buffer nsym wide + states.nsym = N/Ts; % number of symbols in one processing frame + states.nbit = states.nsym*states.bitspersymbol; % number of bits per processing frame + + states.Ndft = (2.^ceil(log2(N)))/2; % find nearest power of 2 for efficient FFT + + Nmem = states.Nmem = N+2*Ts; % two symbol memory in down converted signals to allow for timing adj + + states.Sf = zeros(states.Ndft/2,1); % currentmemory of dft mag samples + states.f_dc = zeros(M,Nmem); + states.P = P; % oversample rate out of filter + assert(Ts/states.P == floor(Ts/states.P), "Ts/P must be an integer"); + + states.nin = N; % can be N +/- Ts/P samples to adjust for sample clock offsets + states.verbose = 0; + states.phi = zeros(1, M); % keep down converter osc phase continuous + + %printf("M: %d Fs: %d Rs: %d Ts: %d nsym: %d nbit: %d\n", states.M, states.Fs, states.Rs, states.Ts, states.nsym, states.nbit); + + % Freq estimator limits + + states.fest_fmax = (Fs/2)-Rs; + states.fest_fmin = Rs/2; + states.fest_min_spacing = 2*(Rs-(Rs/5)); + + % BER stats + + states.ber_state = 0; + states.Tbits = 0; + states.Terrs = 0; + states.nerr_log = 0; + + states.tx_real = 1; + states.dA(1:M) = 1; + states.df(1:M) = 0; + states.f(1:M) = 0; + states.norm_rx_timing = 0; + states.ppm = 0; + states.prev_pkt = []; + + #{ + TODO: fix me to ressuect fks_horus RTTY stuff, maybe call from + % protocol specific states + + states.rtty = fsk_horus_init_rtty_uw(states); + states.binary = fsk_horus_init_binary_uw; + #} + +endfunction + + +% modulator function + +function tx = fsk_mod(states, tx_bits) + + M = states.M; + Ts = states.Ts; + Fs = states.Fs; + ftx = states.ftx; + df = states.df; % tone freq change in Hz/s + dA = states.dA; % amplitude of each tone + + num_bits = length(tx_bits); + num_symbols = num_bits/states.bitspersymbol; + tx = zeros(states.Ts*num_symbols,1); + tx_phase = 0; + s = 1; + + for i=1:states.bitspersymbol:num_bits + + % map bits to FSK symbol (tone number) + + K = states.bitspersymbol; + tone = tx_bits(i:i+(K-1)) * (2.^(K-1:-1:0))' + 1; + + tx_phase_vec = tx_phase + (1:Ts)*2*pi*ftx(tone)/Fs; + tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi; + if states.tx_real + tx((s-1)*Ts+1:s*Ts) = dA(tone)*2.0*cos(tx_phase_vec); + else + tx((s-1)*Ts+1:s*Ts) = dA(tone)*exp(j*tx_phase_vec); + end + s++; + + % freq drift + + ftx += df*Ts/Fs; + end + states.ftx = ftx; +endfunction + + +% Estimate the frequency of the FSK tones. In some applications (such +% as balloon telemtry) these may not be well controlled by the +% transmitter, so we have to try to estimate them. + +function states = est_freq(states, sf, ntones) + N = states.N; + Ndft = states.Ndft; + Fs = states.Fs; + + % This assumption is OK for balloon telemetry but may not be true in + % general + + min_tone_spacing = states.fest_min_spacing; + + % set some limits to search range, which will mean some manual re-tuning + + fmin = states.fest_fmin; + fmax = states.fest_fmax; + st = floor(fmin*Ndft/Fs); + en = floor(fmax*Ndft/Fs); + + % scale averaging time constant based on number of samples + + tc = 0.95*Ndft/Fs; + %tc = .95; + % Update mag DFT --------------------------------------------- + + numffts = floor(length(sf)/Ndft); + h = hanning(Ndft); + for i=1:numffts + a = (i-1)*Ndft+1; b = i*Ndft; + Sf = abs(fft(sf(a:b) .* h, Ndft)); + Sf(1:st) = 0; Sf(en:Ndft/2) = 0; + states.Sf = (1-tc)*states.Sf + tc*Sf(1:Ndft/2); + end + + f = []; a = []; + Sf = states.Sf; + + %figure(8) + %clf + %plot(Sf(1:Ndft/2)); + + % Search for each tone -------------------------------------------------------- + + for m=1:ntones + [tone_amp tone_index] = max(Sf(1:Ndft/2)); + + f = [f (tone_index-1)*Fs/Ndft]; + a = [a tone_amp]; + + % zero out region min_tone_spacing/2 either side of max so we can find next highest peak + % closest spacing for non-coh mFSK is Rs + + st = tone_index - floor((min_tone_spacing/2)*Ndft/Fs); + st = max(1,st); + en = tone_index + floor((min_tone_spacing/2)*Ndft/Fs); + en = min(Ndft/2,en); + Sf(st:en) = 0; + end + + states.f = sort(f); +end + + +% ------------------------------------------------------------------------------------ +% Given a buffer of nin input Rs baud FSK samples, returns nsym bits. +% +% nin is the number of input samples required by demodulator. This is +% time varying. It will nominally be N (8000), and occasionally N +/- +% Ts/2 (e.g. 8080 or 7920). This is how we compensate for differences between the +% remote tx sample clock and our sample clock. This function always returns +% N/Ts (e.g. 50) demodulated bits. Variable number of input samples, constant number +% of output bits. + +function [rx_bits states] = fsk_demod(states, sf) + M = states.M; + N = states.N; + Ndft = states.Ndft; + Fs = states.Fs; + Rs = states.Rs; + Ts = states.Ts; + nsym = states.nsym; + P = states.P; + nin = states.nin; + verbose = states.verbose; + Nmem = states.Nmem; + f = states.f; + + assert(length(sf) == nin); + + % down convert and filter at rate P ------------------------------ + + % update filter (integrator) memory by shifting in nin samples + + nold = Nmem-nin; % number of old samples we retain + + f_dc = states.f_dc; + f_dc(:,1:nold) = f_dc(:,Nmem-nold+1:Nmem); + + % freq shift down to around DC, ensuring continuous phase from last frame + + for m=1:M + phi_vec = states.phi(m) + (1:nin)*2*pi*f(m)/Fs; + f_dc(m,nold+1:Nmem) = sf .* exp(j*phi_vec)'; + states.phi(m) = phi_vec(nin); + states.phi(m) -= 2*pi*floor(states.phi(m)/(2*pi)); + end + + % save filter (integrator) memory for next time + + states.f_dc = f_dc; + + % integrate over symbol period, which is effectively a LPF, removing + % the -2Fc frequency image. Can also be interpreted as an ideal + % integrate and dump, non-coherent demod. We run the integrator at + % rate P*Rs (1/P symbol offsets) to get outputs at a range of + % different fine timing offsets. We calculate integrator output + % over nsym+1 symbols so we have extra samples for the fine timing + % re-sampler at either end of the array. + + for i=1:(nsym+1)*P + st = 1 + (i-1)*Ts/P; + en = st+Ts-1; + for m=1:M + f_int(m,i) = sum(f_dc(m,st:en)); + end + end + states.f_int = f_int; + + % fine timing estimation ----------------------------------------------- + + % Non linearity has a spectral line at Rs, with a phase + % related to the fine timing offset. See: + % http://www.rowetel.com/blog/?p=3573 + % We have sampled the integrator output at Fs=P samples/symbol, so + % lets do a single point DFT at w = 2*pi*f/Fs = 2*pi*Rs/(P*Rs) + % + % Note timing non-lineariry derived by experiment. Not quite sure what I'm doing here..... + % but it gives 0dB impl loss for 2FSK Eb/No=9dB, testmode 1: + % Fs: 8000 Rs: 50 Ts: 160 nsym: 50 + % frames: 200 Tbits: 9700 Terrs: 93 BER 0.010 + + Np = length(f_int(1,:)); + w = 2*pi*(Rs)/(P*Rs); + timing_nl = sum(abs(f_int(:,:)).^2); + x = timing_nl * exp(-j*w*(0:Np-1))'; + norm_rx_timing = angle(x)/(2*pi); + rx_timing = norm_rx_timing*P; + + states.x = x; + states.timing_nl = timing_nl; + states.rx_timing = rx_timing; + prev_norm_rx_timing = states.norm_rx_timing; + states.norm_rx_timing = norm_rx_timing; + + % estimate sample clock offset in ppm + % d_norm_timing is fraction of symbol period shift over nsym symbols + + d_norm_rx_timing = norm_rx_timing - prev_norm_rx_timing; + + % filter out big jumps due to nin changes + + if abs(d_norm_rx_timing) < 0.2 + appm = 1E6*d_norm_rx_timing/nsym; + states.ppm = 0.9*states.ppm + 0.1*appm; + end + + % work out how many input samples we need on the next call. The aim + % is to keep angle(x) away from the -pi/pi (+/- 0.5 fine timing + % offset) discontinuity. The side effect is to track sample clock + % offsets + + next_nin = N; + if norm_rx_timing > 0.25 + next_nin += Ts/2; + end + if norm_rx_timing < -0.25; + next_nin -= Ts/2; + end + states.nin = next_nin; + + % Now we know the correct fine timing offset, Re-sample integrator + % outputs using fine timing estimate and linear interpolation, then + % extract the demodulated bits + + low_sample = floor(rx_timing); + fract = rx_timing - low_sample; + high_sample = ceil(rx_timing); + + if bitand(verbose,0x2) + printf("rx_timing: %3.2f low_sample: %d high_sample: %d fract: %3.3f nin_next: %d\n", rx_timing, low_sample, high_sample, fract, next_nin); + end + + f_int_resample = zeros(M,nsym); + rx_bits = zeros(1,nsym*states.bitspersymbol); + tone_max = rx_bits_sd = zeros(1,nsym); + + for i=1:nsym + st = i*P+1; + f_int_resample(:,i) = f_int(:,st+low_sample)*(1-fract) + f_int(:,st+high_sample)*fract; + + % Largest amplitude tone is the winner. Map this FSK "symbol" back to a bunch-o-bits, + % depending on M. + + [tone_max(i) tone_index] = max(f_int_resample(:,i)); + st = (i-1)*states.bitspersymbol + 1; + en = st + states.bitspersymbol-1; + arx_bits = dec2bin(tone_index - 1, states.bitspersymbol) - '0'; + rx_bits(st:en) = arx_bits; + end + + states.f_int_resample = f_int_resample; + states.rx_bits_sd = rx_bits_sd; + + % Eb/No estimation (todo: this needs some work, like calibration, low Eb/No perf) + + tone_max = abs(tone_max); + states.EbNodB = -6 + 20*log10(1E-6+mean(tone_max)/(1E-6+std(tone_max))); +endfunction + + +% BER counter and test frame sync logic ------------------------------------------- + +function states = ber_counter(states, test_frame, rx_bits_buf) + nbit = states.nbit; + state = states.ber_state; + next_state = state; + + if state == 0 + + % try to sync up with test frame + + nerrs_min = nbit; + for i=1:nbit + error_positions = xor(rx_bits_buf(i:nbit+i-1), test_frame); + nerrs = sum(error_positions); + if nerrs < nerrs_min + nerrs_min = nerrs; + states.coarse_offset = i; + end + end + if nerrs_min/nbit < 0.05 + next_state = 1; + end + if bitand(states.verbose,0x4) + printf("coarse offset: %d nerrs_min: %d next_state: %d\n", states.coarse_offset, nerrs_min, next_state); + end + end + + if state == 1 + + % we're synced up, lets measure bit errors + + error_positions = xor(rx_bits_buf(states.coarse_offset:states.coarse_offset+nbit-1), test_frame); + nerrs = sum(error_positions); + if nerrs/nbit > 0.1 + next_state = 0; + else + states.Terrs += nerrs; + states.Tbits += nbit; + states.nerr_log = [states.nerr_log nerrs]; + end + end + + states.ber_state = next_state; +endfunction + + +% Alternative stateless BER counter that works on packets that may have gaps between them + +function states = ber_counter_packet(states, test_frame, rx_bits_buf) + ntestframebits = states.ntestframebits; + nbit = states.nbit; + + % look for offset with min errors + + nerrs_min = ntestframebits; coarse_offset = 1; + for i=1:nbit + error_positions = xor(rx_bits_buf(i:ntestframebits+i-1), test_frame); + nerrs = sum(error_positions); + %printf("i: %d nerrs: %d\n", i, nerrs); + if nerrs < nerrs_min + nerrs_min = nerrs; + coarse_offset = i; + end + end + + % if less than threshold count errors + + if nerrs_min/ntestframebits < 0.05 + states.Terrs += nerrs_min; + states.Tbits += ntestframebits; + states.nerr_log = [states.nerr_log nerrs_min]; + if bitand(states.verbose, 0x4) + printf("coarse_offset: %d nerrs_min: %d\n", coarse_offset, nerrs_min); + end + end +endfunction + + diff --git a/codec2/branches/0.7/octave/fskdemodgui.py b/codec2/branches/0.7/octave/fskdemodgui.py new file mode 100644 index 00000000..0ee182aa --- /dev/null +++ b/codec2/branches/0.7/octave/fskdemodgui.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python +# +# fsk_demod Statistics GUI +# Accepts the stats output from fsk_demod on stdin, and plots it. +# +# Mark Jessop 2016-03-13 +# +# NOTE: This is intended to be run on a 'live' stream of samples, and hence expects +# updates at about 10Hz. Anything faster will fill up the input queue and be discarded. +# +# Call using: +# | ./fsk_demod 2X 8 923096 115387 - - S 2> >(python ~/Dev/codec2-dev/octave/fskdemodgui.py) | +# +# +import sys, time, json, Queue, argparse +from threading import Thread +from pyqtgraph.Qt import QtGui, QtCore +import numpy as np +import pyqtgraph as pg + +parser = argparse.ArgumentParser() +parser.add_argument("--wide", action="store_true", default=False, help="Alternate wide arrangement of widgets, for placement at bottom of 4:3 screen.") +args = parser.parse_args() + +# Some settings... +update_rate = 2 # Hz +history_size = 100 # 10 seconds at 10Hz... +history_scale = np.linspace((-1*history_size+1)/float(update_rate),0,history_size) + +# Input queue +in_queue = Queue.Queue(1) # 1-element FIFO... + +win = pg.GraphicsWindow() +win.setWindowTitle('FSK Demodulator Modem Statistics') + + +# Plot objects +ebno_plot = win.addPlot(title="Eb/No") +ppm_plot = win.addPlot(title="Sample Clock Offset") +if args.wide == False: + win.nextRow() +else: + win.resize(1024,200) +fest_plot =pg.PlotItem() # win.addPlot(title="Tone Frequency Estimation") +eye_plot = win.addPlot(title="Eye Diagram") +# Disable auto-ranging on eye plot and fix axes for a big speedup... +spec_plot = win.addPlot(title="Spectrum") +spec_plot.setYRange(0,40) +spec_plot.setLabel('left','SNR (dB)') +spec_plot.setLabel('bottom','FFT Bin') +# Configure plot labels and scales. +ebno_plot.setLabel('left','Eb/No (dB)') +ebno_plot.setLabel('bottom','Time (seconds)') +ebno_plot.setYRange(0,25) +ppm_plot.setLabel('left','Clock Offset (ppm)') +ppm_plot.setLabel('bottom','Time (seconds)') +fest_plot.setLabel('left','Frequency (Hz)') +fest_plot.setLabel('bottom','Time (seconds)') +eye_plot.disableAutoRange() +eye_plot.setYRange(0,1) +eye_plot.setXRange(0,15) +eye_xr = 15 + +# Data arrays... +ebno_data = np.zeros(history_size)*np.nan +ppm_data = np.zeros(history_size)*np.nan +fest_data = np.zeros((4,history_size))*np.nan + +# Curve objects, so we can update them... +spec_curve = spec_plot.plot([0]) +ebno_curve = ebno_plot.plot(x=history_scale,y=ebno_data) +ppm_curve = ppm_plot.plot(x=history_scale,y=ppm_data) +fest1_curve = fest_plot.plot(x=history_scale,y=fest_data[0,:],pen='r') # f1 = Red +fest2_curve = fest_plot.plot(x=history_scale,y=fest_data[1,:],pen='g') # f2 = Blue +fest3_curve = fest_plot.plot(x=history_scale,y=fest_data[2,:],pen='b') # f3 = Greem +fest4_curve = fest_plot.plot(x=history_scale,y=fest_data[3,:],pen='m') # f4 = Magenta + +# Plot update function. Reads from queue, processes and updates plots. +def update_plots(): + global timeout,timeout_counter,eye_plot,ebno_curve, ppm_curve, fest1_curve, fest2_curve, ebno_data, ppm_data, fest_data, in_queue, eye_xr, spec_curve + + try: + if in_queue.empty(): + return + in_data = in_queue.get_nowait() + in_data = json.loads(in_data) + except Exception as e: + + sys.stderr.write(str(e)) + return + + # Roll data arrays + ebno_data[:-1] = ebno_data[1:] + ppm_data[:-1] = ppm_data[1:] + fest_data = np.roll(fest_data,-1,axis=1) + + + # Try reading in the new data points from the dictionary. + try: + new_ebno = in_data['EbNodB'] + new_ppm = in_data['ppm'] + new_fest1 = in_data['f1_est'] + new_fest2 = in_data['f2_est'] + new_spec = in_data['samp_fft'] + except Exception as e: + print("ERROR reading dict: %s" % e) + + # Try reading in the other 2 tones. + try: + new_fest3 = in_data['f3_est'] + new_fest4 = in_data['f4_est'] + fest_data[2,-1] = new_fest3 + fest_data[3,-1] = new_fest4 + except: + # If we can't read these tones out of the dict, fill with NaN + fest_data[2,-1] = np.nan + fest_data[3,-1] = np.nan + + # Add in new data points + ebno_data[-1] = new_ebno + ppm_data[-1] = new_ppm + fest_data[0,-1] = new_fest1 + fest_data[1,-1] = new_fest2 + + # Update plots + spec_data_log = 20*np.log10(np.array(new_spec)+0.01) + spec_curve.setData(spec_data_log) + spec_plot.setYRange(spec_data_log.max()-50,spec_data_log.max()+10) + ebno_curve.setData(x=history_scale,y=ebno_data) + ppm_curve.setData(x=history_scale,y=ppm_data) + fest1_curve.setData(x=history_scale,y=fest_data[0,:],pen='r') # f1 = Red + fest2_curve.setData(x=history_scale,y=fest_data[1,:],pen='g') # f2 = Blue + fest3_curve.setData(x=history_scale,y=fest_data[2,:],pen='b') # f3 = Green + fest4_curve.setData(x=history_scale,y=fest_data[3,:],pen='m') # f4 = Magenta + + #Now try reading in and plotting the eye diagram + try: + eye_data = np.array(in_data['eye_diagram']) + + #eye_plot.disableAutoRange() + eye_plot.clear() + col_index = 0 + for line in eye_data: + eye_plot.plot(line,pen=(col_index,eye_data.shape[0])) + col_index += 1 + #eye_plot.autoRange() + + #Quick autoranging for x-axis to allow for differing P and Ts values + if eye_xr != len(eye_data[0]) - 1: + eye_xr = len(eye_data[0]) - 1 + eye_plot.setXRange(0,len(eye_data[0])-1) + + except Exception as e: + pass + + +timer = pg.QtCore.QTimer() +timer.timeout.connect(update_plots) +timer.start(1000/update_rate) + + +# Thread to read from stdin and push into a queue to be processed. +def read_input(): + global in_queue + + while True: + in_line = sys.stdin.readline() + + # Only push actual data into the queue... + # This stops sending heaps of empty strings into the queue when fsk_demod closes. + if in_line == "": + time.sleep(0.1) + continue + + if not in_queue.full(): + in_queue.put_nowait(in_line) + +read_thread = Thread(target=read_input) +read_thread.daemon = True # Set as daemon, so when all other threads die, this one gets killed too. +read_thread.start() + +## Start Qt event loop unless running in interactive mode or using pyside. +if __name__ == '__main__': + import sys + if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + try: + QtGui.QApplication.instance().exec_() + except KeyboardInterrupt: + sys.exit(0) diff --git a/codec2/branches/0.7/octave/fuzzy_gray.m b/codec2/branches/0.7/octave/fuzzy_gray.m new file mode 100644 index 00000000..425f8d7c --- /dev/null +++ b/codec2/branches/0.7/octave/fuzzy_gray.m @@ -0,0 +1,586 @@ +% fuzzy_gray.m +% David Rowe +% 10 April 2014 +% +% Various experiments in fuzzy gray codes and quantising and +% transmitting scalars. + +1; + +% fuzzy gray coding idea: use an extra parity bit, if we get a single +% bit error the value will be "close: to the original, so effect of +% error will be soft. Unlike data we don't need 0 bit errors. I +% struggled to extend this to larger m. + +function three_bit_code + m=4; + log2_m=2; + value_to_codeword = ["000"; "001"; "101"; "111"]; + codeword_to_value = [0 1 1 2 1 2 2 3 3]; + + printf("tx_value tx_codeword rx_codeword rx_value distance\n"); + for i=1:m + tx_codeword = bin2dec(value_to_codeword(i,:)); + tx_codeword_bin = value_to_codeword(i,:); + rx_value = codeword_to_value(tx_codeword+1); + distance = abs((i-1) - rx_value); + printf("%8d %11s %11s %8d %8d\n", i-1, tx_codeword_bin, tx_codeword_bin, ... + rx_value, distance ); + end + printf("\n"); + for i=1:m + tx_codeword = bin2dec(value_to_codeword(i,:)); + tx_codeword_bin = value_to_codeword(i,:); + for j=1:(log2_m+1) + rx_codeword = bitxor(tx_codeword, bitset(0,j)); + rx_codeword_bin = dec2bin(rx_codeword, 3); + rx_value = codeword_to_value(rx_codeword+1); + distance = abs((i-1) - rx_value); + printf("%8d %11s %11s %8d %8d\n", i-1, tx_codeword_bin, rx_codeword_bin, ... + rx_value, distance ); + end + end +endfunction + +% regular natural binary quantiser + +function index = quantise_value(value, min_value, max_value, num_levels) + norm = (value - min_value)/(max_value - min_value); + index = floor(num_levels * norm + 0.5); + if (index < 0 ) + index = 0; + end + if (index > (num_levels-1)) + index = num_levels-1; + end +endfunction + +function value = unquantise_value(index, min_value, max_value, num_levels) + step = (max_value - min_value)/num_levels; + value = min_value + step*(index); +endfunction + +% converting natural binary to gray + +function gray = binary_to_gray(natural) + gray = bitxor(bitshift(natural,-1),natural); +endfunction + +function natural = gray_to_binary(gray) + for i=1:length(gray) + mask = bitshift(gray(i),-1); + num = gray(i); + while(mask) + num = bitxor(num, mask); + mask = bitshift(mask,-1); + end + natural(i) = num; + end +endfunction + +function sim_out = test_baseline_uncoded(Ebvec, Nbits, Ntrials, enable_error_log, enable_gray) + Nlevels = 2.^ Nbits; powersOfTwo = 2 .^ fliplr(0:(Nbits-1)); + Nsymb = Nbits; + + sim_out.qnoise_log = zeros(length(Ebvec),Ntrials); + sim_out.error_log = []; + + for ne = 1:length(Ebvec) + EbNodB = Ebvec(ne); + EbNo = 10^(EbNodB/10); + + variance = 1/EbNo; + + Terrs = 0; Tbits = 0; + qsignal = qnoise = 0; + + for nn = 1:Ntrials + + tx_value = rand(1,1); + tx_index = quantise_value(tx_value, 0, 1, Nlevels); + if enable_gray + tx_index = binary_to_gray(tx_index); + end + tx_bits = dec2bin(tx_index, Nbits) - '0'; + tx_symbols = -1 + 2*tx_bits; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + rx_symbols = tx_symbols + noise; + + rx_bits = rx_symbols > 0; + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + if enable_error_log + sim_out.error_log = [sim_out.error_log error_positions]; + end + + rx_index = (powersOfTwo * rx_bits'); + if enable_gray + rx_index = gray_to_binary(rx_index); + end + rx_value = unquantise_value(rx_index, 0, 1, Nlevels); + + qsignal += tx_value*tx_value; + qnoise += (tx_value - rx_value) .^ 2; + sim_out.qnoise_log(ne,nn) = tx_value - rx_value; + end + + sim_out.TERvec(ne) = Terrs; + sim_out.BERvec(ne) = Terrs/Tbits; + sim_out.QSNRvec(ne) = 10*log10(qsignal/qnoise); + printf("EbNo (dB): %3.2f Terrs: %6d BER %1.4f QSNR (dB): %3.2f\n", + EbNodB, Terrs, Terrs/Tbits, 10*log10(qsignal/qnoise)); + end + +endfunction + +function sim_out = test_varpower(Ebvec, Nbits, Ntrials, amps, enable_error_log) + Nlevels = 2.^ Nbits; powersOfTwo = 2 .^ fliplr(0:(Nbits-1)); + Nsymb = Nbits; + + sim_out.qnoise_log = zeros(length(Ebvec), Ntrials); + sim_out.error_log = []; + + for ne = 1:length(Ebvec) + EbNodB = Ebvec(ne); + EbNo = 10^(EbNodB/10); + + variance = 1/EbNo; + + Terrs = 0; Tbits = 0; + qsignal = qnoise = 0; + + for nn = 1:Ntrials + + tx_value = rand(1,1); + tx_index = quantise_value(tx_value, 0, 1, Nlevels); + tx_bits = dec2bin(tx_index, Nbits) - '0'; + tx_symbols = (-1 + 2*tx_bits) .* amps; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + rx_symbols = tx_symbols + noise; + + rx_bits = rx_symbols > 0; + + error_positions = xor(rx_bits, tx_bits); + if enable_error_log + sim_out.error_log = [sim_out.error_log error_positions]; + end + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + + rx_index = (powersOfTwo * rx_bits'); + rx_value = unquantise_value(rx_index, 0, 1, Nlevels); + + qsignal += tx_value*tx_value; + qnoise += (tx_value - rx_value) .^ 2; + sim_out.qnoise_log(ne,nn) = tx_value - rx_value; + end + + sim_out.TERvec(ne) = Terrs; + sim_out.BERvec(ne) = Terrs/Tbits; + sim_out.QSNRvec(ne) = 10*log10(qsignal/qnoise); + printf("EbNo (dB): %3.2f Terrs: %6d BER %1.4f QSNR (dB): %3.2f\n", + EbNodB, Terrs, Terrs/Tbits, 10*log10(qsignal/qnoise)); + end + +endfunction + +% gray codes with specified number of data and parity bits. Soft +% decision decoding. Didn't really work out. + +function valid_codewords = fuzzy_code_create(ndata,nparity) + Nbits = ndata + nparity; + Nvalid = 2 .^ ndata; + codewords = binary_to_gray(0:(2 .^ Nbits)-1); + valid_codewords = dec2bin(codewords(1:2:(2 .^ Nbits)), Nbits) - '0'; + + % check all valid codewords have a hamming distance of at least 2^nparity + + bad_distance = 0; + for i=1:Nvalid + for k=i+1:Nvalid + distance = sum(bitxor(valid_codewords(i,:), valid_codewords(k,:))); + if distance < 2 + bad_distance++; + end + end + end + if bad_distance != 0 + printf("Error: Nvalid: %d bad_distance: %d\n", Nvalid, bad_distance); + return; + end + +endfunction + +function tx_codeword = fuzzy_code_encode(codewords, value) + tx_codeword = codewords(value+1,:); +endfunction + +function [value, best_codeword] = fuzzy_code_decode(codewords, rx_symbols) + max_corr = 0; + value = 0; + [rows,cols] = size(codewords); + for i=1:rows + corr = (-1 + 2*codewords(i,:)) * transpose(rx_symbols); + if (corr > max_corr) + max_corr = corr; + value = i-1; + best_codeword = codewords(i,:); + end + end +endfunction + + +function sim_out = test_fuzzy_code(Ebvec, Ndata, Nparity, Ntrials) + Nbits = Ndata + Nparity; + Nlevels = 2 .^ Ndata; + Nsymb = Nbits; + powersOfTwo = 2 .^ fliplr(0:(Nbits-1)); + + codewords = fuzzy_code_create(Ndata,Nparity); + sim_out.qnoise_log = zeros(length(Ebvec), Ntrials); + + for ne = 1:length(Ebvec) + EbNodB = Ebvec(ne); + EbNo = 10^(EbNodB/10); + + variance = 1/EbNo; + + Terrs = 0; Terrs_coded = 0; Tbits = 0; + Nsingle = Nsingle_corrected = 0; + qsignal = qnoise = 0; + + for nn = 1:Ntrials + + tx_value = rand(1,1); + tx_index = quantise_value(tx_value, 0, 1, Nlevels); + tx_codeword = fuzzy_code_encode(codewords, tx_index); + tx_symbols = -1 + 2*tx_codeword; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + rx_symbols = tx_symbols + noise; + + % uncoded BER + + rx_bits = rx_symbols > 0; + error_positions = xor(rx_bits(1:Ndata), tx_codeword(1:Ndata)); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += Ndata; + + % decode and determine QSNR + + [rx_index, rx_codeword] = fuzzy_code_decode(codewords, rx_symbols); + rx_value = unquantise_value(rx_index, 0, 1, Nlevels); + qsignal += tx_value*tx_value; + qnoise += (tx_value - rx_value) .^ 2; + sim_out.qnoise_log(ne,nn) = tx_value - rx_value; + + % coded BER + + error_positions = xor(rx_codeword(1:Ndata), tx_codeword(1:Ndata)); + Nerrs_coded = sum(error_positions); + if Nerrs == 1 + Nsingle++; + if Nerrs_coded == 0 + Nsingle_corrected++; + end + end + Terrs_coded += Nerrs_coded; + + end + + sim_out.BERvec(ne) = Terrs/Tbits; + sim_out.BERvec_coded(ne) = Terrs_coded/Tbits; + sim_out.Nsingle(ne) = Nsingle; + sim_out.Nsingle_corrected(ne) = Nsingle_corrected; + + sim_out.QSNRvec(ne) = 10*log10(qsignal/qnoise); + printf("EbNo (dB): %3.2f Terrs: %6d BER %1.4f Terrs_coded: %6d BER_coded %1.4f QSNR (dB): %3.2f", + EbNodB, Terrs, Terrs/Tbits, Terrs_coded, Terrs_coded/Tbits, sim_out.QSNRvec(ne)); + printf(" Nsingle: %d Nsingle_corrected: %d corrected: %3.1f\n", Nsingle, Nsingle_corrected, Nsingle_corrected*100/Nsingle); + end +endfunction + +function compare_baseline_fuzzy + Ebvec = 0:3; + Ntrials = 5000; + Nbits = 4; Nparity = 1; + + baseline = test_baseline_uncoded(Ebvec, Nbits, Ntrials, 0, 0); + fuzzy = test_fuzzy_code(Ebvec, Nbits, Nparity, Ntrials); + + figure(1); + clf; + semilogy(Ebvec, baseline.BERvec) + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + + figure(2); + clf; + plot(Ebvec, baseline.QSNRvec,'b;baseline;') + hold on; + plot(Ebvec, fuzzy.QSNRvec,'r;fuzzy;') + hold off; + xlabel('Eb/N0') + ylabel('SNR') + grid("minor") + + figure(3); + subplot(211) + hist(baseline.qnoise_log(4,:),50); + subplot(212) + hist(fuzzy.qnoise_log(4,:),50); + + figure(4) + subplot(211) + plot(baseline.qnoise_log(4,1:250),'b;baseline;') + subplot(212) + plot(fuzzy.qnoise_log(4,1:250),'r;fuzzy;') +endfunction + +% compare baseline and variable power schemes and make plots + +function compare_baseline_varpower_plot + Ebvec = -2:5; + Ntrials = 5000; + Nbits = 5; + + baseline = test_baseline_uncoded(Ebvec, Nbits, Ntrials, 0, 0); + amps = [2 1.5 1.0 0.5 0.5]; + av_pwr = (amps*amps')/length(amps); + amps_norm = amps/sqrt(av_pwr); + varpower = test_varpower(Ebvec, Nbits, Ntrials, amps_norm, 0); + + figure(1); + clf; + semilogy(Ebvec, baseline.BERvec) + xlabel('Eb/No (dB)') + ylabel('BER') + grid("minor") + title('BER versus Eb/No') + + figure(2); + clf; + plot(Ebvec, baseline.QSNRvec,'b;baseline;') + hold on; + plot(Ebvec, varpower.QSNRvec,'r;varpower;') + hold off; + xlabel('Eb/No (dB)') + ylabel('SNR (dB)') + grid("minor") + title('Quantiser SNR versus Eb/No') + + figure(3); + subplot(211) + hist(baseline.qnoise_log(1,:),50); + title('Baseline and Variable Power Error Histograms') + subplot(212) + hist(varpower.qnoise_log(1,:),50); + + figure(4) + subplot(211) + plot(baseline.qnoise_log(1,1:250),'b;baseline;') + title('Baseline and Variable Power Error plots for Eb/No = -2dB') + subplot(212) + plot(varpower.qnoise_log(1,1:250),'r;varpower;') +endfunction + +% Compare baseline and variable power schemes and make error pattern +% files for inserting into codec bit stream so we can listen to +% result. + +function compare_baseline_varpower_error_files + Ebvec = -2; + Fs = 25; % number of samples per second + Nsec = 15; % seconds to simulate + Ntrials = Fs*Nsec; + Nbits = 5; + bits_per_frame = 52; + bits_per_frame_rounded = ceil(bits_per_frame/8)*8; % c2enc uses integer number of bytes/frame + start_bit = 12; % first energy bit (after 4 voicing, 7 Wo bits) + + baseline = test_baseline_uncoded(Ebvec, Nbits, Ntrials, 1, 0); + amps = [2 1.5 1.0 0.5 0.5]; + av_pwr = (amps*amps')/length(amps); + amps_norm = amps/sqrt(av_pwr); + varpower = test_varpower(Ebvec, Nbits, Ntrials, amps_norm, 1); + + % construct error patterns to apply to c2enc bit stream + + baseline_errors = []; + for i=1:Ntrials + error_positions = baseline.error_log(Nbits*(i-1)+1:Nbits*i); + baseline_errors = [baseline_errors zeros(1,start_bit-1) error_positions ... + zeros(1, bits_per_frame_rounded - Nbits - (start_bit-1))]; + end + + varpower_errors = []; + for i=1:Ntrials + error_positions = varpower.error_log(Nbits*(i-1)+1:Nbits*i); + varpower_errors = [varpower_errors zeros(1,start_bit-1) error_positions ... + zeros(1, bits_per_frame_rounded - Nbits - (start_bit-1))]; + end + + % save error patterns + + fep=fopen("energy_errors_baseline.bin","wb"); fwrite(fep, baseline_errors, "short"); fclose(fep); + fep=fopen("energy_errors_varpower.bin","wb"); fwrite(fep, varpower_errors, "short"); fclose(fep); +endfunction + +% compare natural and gray coding and make plots + +function compare_natural_gray_plot + Ebvec = -2:10; + Ntrials = 5000; + Nbits = 7; + + natural = test_baseline_uncoded(Ebvec, Nbits, Ntrials, 0, 0); + gray = test_baseline_uncoded(Ebvec, Nbits, Ntrials, 0, 1); + + figure(1); + clf; + semilogy(Ebvec, natural.BERvec) + xlabel('Eb/No (dB)') + ylabel('BER') + grid("minor") + title('BER versus Eb/No') + + figure(2); + clf; + plot(Ebvec, natural.QSNRvec,'b;natural;') + hold on; + plot(Ebvec, gray.QSNRvec,'r;gray;') + hold off; + xlabel('Eb/No (dB)') + ylabel('SNR (dB)') + grid("minor") + title('Quantiser SNR versus Eb/No') + + figure(3); + subplot(211) + hist(natural.qnoise_log(1,:),50); + title('Natural and Gray coded Error Histograms') + subplot(212) + hist(gray.qnoise_log(1,:),50); + + figure(4) + subplot(211) + plot(natural.qnoise_log(1,1:250),'b;natural;') + axis([0 250 -1 1]) + title('Natural and Gray coded Error plots for Eb/No = -2dB') + subplot(212) + plot(gray.qnoise_log(1,1:250),'r;gray;') + axis([0 250 -1 1]) +endfunction + +% compare natural at different Eb/No and Nbitsmake plots + +function compare_natural_nbit_plot + Ebvec = -2:10; + Ntrials = 5000; + + figure(1); + clf; + for n = 2:7 + natural = test_baseline_uncoded(Ebvec, n, Ntrials, 0, 0); + plot(Ebvec, natural.QSNRvec) + if n == 2 + hold on; + end + end + hold off; + + xlabel('Eb/No (dB)') + ylabel('SNR (dB)') + grid("minor") + title('Quantiser SNR versus Eb/No') +endfunction + +function generate_varpower_error_files(EbNo, start_bit, end_bit, amps, error_file_name) + Fs = 25; % number of samples per second + Nsec = 3; % seconds to simulate + Ntrials = Fs*Nsec; + Nbits = end_bit - start_bit + 1; + bits_per_frame = 52; + bits_per_frame_rounded = ceil(bits_per_frame/8)*8; % c2enc uses integer number of bytes/frame + % first energy bit (after 4 voicing, 7 Wo bits) + + % normalise powers and run test + + av_pwr = (amps*amps')/length(amps); + amps_norm = amps/sqrt(av_pwr); + av_pwr2 = (amps_norm*amps_norm')/length(amps_norm) + varpower = test_varpower(EbNo, Nbits, Ntrials, amps_norm, 1); + + % construct error patterns to apply to c2enc bit stream + + varpower_errors = []; + for i=1:Ntrials + error_positions = varpower.error_log(Nbits*(i-1)+1:Nbits*i); + + if 0 + % reset single errors to tes effect of ideal single bit error correcting code + for i=1:7 + st = 4*(i-1)+1 + en = 4*i + if sum(error_positions(st:en)) == 1 + error_positions(st:en) = 0; + end + end + for i=1:2 + st = 7*4+3*(i-1)+1 + en = 7*4+3*i + if sum(error_positions(st:en)) == 1 + error_positions(st:en) = 0; + end + end + st = 7*4+3*2+1 + en = 7*4+3*2+2 + if sum(error_positions(st:en)) == 1 + error_positions(st:en) = 0; + end + end + + num_errors(i) = sum(error_positions); + varpower_errors = [varpower_errors zeros(1,start_bit-1) error_positions ... + zeros(1, bits_per_frame_rounded - Nbits - (start_bit-1))]; + end + + % save error pattern to file + + fep=fopen(error_file_name,"wb"); fwrite(fep, varpower_errors, "short"); fclose(fep); + + figure(1) + clf + hist(num_errors) +endfunction + +more off; + +%generate_varpower_error_files(0, 17, 52, ones(1,36), "lsp_baseline_errors_0dB.bin") +%amps = [1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1 1 1 1 1 1 ]; +%generate_varpower_error_files(0, 17, 52, amps, "lsp_varpower_errors_0dB.bin") + +%compare_natural_nbit_plot +%compare_natural_gray_plot +%compare_baseline_varpower_plot +%compare_baseline_varpower_error_files + +compare_baseline_fuzzy +%fuzzy_code_create(3,1) diff --git a/codec2/branches/0.7/octave/gen_complex_short.m b/codec2/branches/0.7/octave/gen_complex_short.m new file mode 100644 index 00000000..2513f055 --- /dev/null +++ b/codec2/branches/0.7/octave/gen_complex_short.m @@ -0,0 +1,18 @@ +% gen_complex_short.m +% +% David Rowe Feb 2017 +% +% Generates a complex short signal for HackRF testing. + +Fs = 8E3; +T = 10; +A = 32000; +f = 1000; + +N = T*Fs; +t = 0:N-1; +s = A*exp(j*2*pi*t*f/Fs); +scomp = zeros(1,2*N); +scomp(1:2:2*N) = real(s); +scomp(2:2:2*N) = imag(s); +save_raw("twotone.iq16",scomp); diff --git a/codec2/branches/0.7/octave/gen_rn_coeffs.m b/codec2/branches/0.7/octave/gen_rn_coeffs.m new file mode 100644 index 00000000..bfc214e0 --- /dev/null +++ b/codec2/branches/0.7/octave/gen_rn_coeffs.m @@ -0,0 +1,40 @@ +% gen_rn_coeffs.m +% David Rowe 13 april 2012 +% +% Generate root raised cosine (Root Nyquist) filter coefficients +% thanks http://www.dsplog.com/db-install/wp-content/uploads/2008/05/raised_cosine_filter.m + +function coeffs = gen_rn_coeffs(alpha, T, Rs, Nsym, M) + + Ts = 1/Rs; + + n = -Nsym*Ts/2:T:Nsym*Ts/2; + Nfilter = Nsym*M; + Nfiltertiming = M+Nfilter+M; + + sincNum = sin(pi*n/Ts); % numerator of the sinc function + sincDen = (pi*n/Ts); % denominator of the sinc function + sincDenZero = find(abs(sincDen) < 10^-10); + sincOp = sincNum./sincDen; + sincOp(sincDenZero) = 1; % sin(pix/(pix) =1 for x =0 + + cosNum = cos(alpha*pi*n/Ts); + cosDen = (1-(2*alpha*n/Ts).^2); + cosDenZero = find(abs(cosDen)<10^-10); + cosOp = cosNum./cosDen; + cosOp(cosDenZero) = pi/4; + gt_alpha5 = sincOp.*cosOp; + Nfft = 4096; + GF_alpha5 = fft(gt_alpha5,Nfft)/M; + + % sqrt causes stop band to be amplified, this hack pushes it down again + + for i=1:Nfft + if (abs(GF_alpha5(i)) < 0.02) + GF_alpha5(i) *= 0.001; + endif + end + GF_alpha5_root = sqrt(abs(GF_alpha5)) .* exp(j*angle(GF_alpha5)); + ifft_GF_alpha5_root = ifft(GF_alpha5_root); + coeffs = real((ifft_GF_alpha5_root(1:Nfilter))); +endfunction diff --git a/codec2/branches/0.7/octave/glottal.m b/codec2/branches/0.7/octave/glottal.m new file mode 100644 index 00000000..46675e7d --- /dev/null +++ b/codec2/branches/0.7/octave/glottal.m @@ -0,0 +1,29 @@ +% glottal.m +% David Rowe 12 Sep 2009 +% Matlab script to generate the phase spectra of a glottal pulse + +% lpc10 pulse from spandsp. When the file glottal.c was used as a part of the +% excitation phase component in phase.c, phase_synth_zero_order(), no difference +% in speech quality was apparent. So left out of code for now. + +sh=12 +kexc = [ 8, -16, 26, -48, 86, -162, 294, -502, 718, -728, 184 672, -610, -672, 184, 728, 718, 502, 294, 162, 86, 48, 26, 16, 8]; +kexc = shift(kexc,sh); +kexc = [kexc(1:sh) zeros(1,512-25) kexc(sh+1:25)]; +figure(1) +clf +plot(kexc) +figure(2) +G = fft(kexc); +subplot(211) +plot((1:256)*(4000/256),unwrap(angle(G(1:256)))) +subplot(212) +plot(20*log10(abs(G))) + +f=fopen("glottal.c","wt"); +fprintf(f,"const float glottal[]={\n"); +for m=1:255 + fprintf(f," %f,\n",angle(G(m))); +endfor +fprintf(f," %f};\n",angle(G(256))); +fclose(f); diff --git a/codec2/branches/0.7/octave/gmsk.m b/codec2/branches/0.7/octave/gmsk.m new file mode 100644 index 00000000..5f07d444 --- /dev/null +++ b/codec2/branches/0.7/octave/gmsk.m @@ -0,0 +1,1021 @@ +% gmsk.m +% David Rowe Dec 2014 +% +% GMSK modem implementation and simulations to test + +% +% [X] plot eye diagram +% [X] BER curves with reas match to theoretical +% [X] fine timing estimator +% [X] test with fine timing error by resampling +% [X] phase/freq estimator +% + need initial acquisition and tracking +% [X] test with different freq offsets +% [X] coarse timing estimator (sync up to known test frames) +% [X] test with different coarse timing offsets +% [ ] file read/write interface +% [ ] refactor into tx/rx functions +% [X] modify for 1200 (or any) bit/s operation +% + ie GMSK filter coeff generation +% + or just re-sampling? e.g. ratio of Fs to Rs? +% [ ] way to measure input SNR to demod +% + Maybe based on test tone/carrier from the other side? +% + think about process ... total signal plus noise power? Increase power until S+N doubles? +% [X] generate curves for baseline modem and with sync algorithms +% [X] used coarse sync code to remove need for knowing delays +% [X] demod level indep +% + scaled OK +/- 20dB same BER +% [X] effect of DC signals from SDRs +% + simulated effect of general interferer at -1500Hz, at an amplitude of 4 +% (12 dB above GMSK signal), it started to affect BER e.g. 0.007 to 0.009 +% Line appeared about 30dB above top of GMSK signal. +% [ ] effect of quantisation noise + +% Filter coeffs From: +% https://github.com/on1arf/gmsk/blob/master/gmskmodem_codec2/API/a_dspstuff.h, +% which is in turn from Jonathan G4KLX. The demod coeffs low pass filter noise + +global gmsk_mod_coeff = [... + 6.455906007234699e-014, 1.037067381285011e-012, 1.444835156335346e-011,... +1.745786683011439e-010, 1.829471305298363e-009, 1.662729407135958e-008,... +1.310626978701910e-007, 8.959797186410516e-007, 5.312253663302771e-006,... +2.731624380156465e-005, 1.218217140199093e-004, 4.711833994209542e-004,... +1.580581180127418e-003, 4.598383433830095e-003, 1.160259430889949e-002,... +2.539022692626253e-002, 4.818807833062393e-002, 7.931844341164322e-002,... +1.132322945270602e-001, 1.401935338024111e-001, 1.505383695578516e-001,... +1.401935338024111e-001, 1.132322945270601e-001, 7.931844341164328e-002,... +4.818807833062393e-002, 2.539022692626253e-002, 1.160259430889949e-002,... +4.598383433830090e-003, 1.580581180127420e-003, 4.711833994209542e-004,... +1.218217140199093e-004, 2.731624380156465e-005, 5.312253663302753e-006,... +8.959797186410563e-007, 1.310626978701910e-007, 1.662729407135958e-008,... +1.829471305298363e-009, 1.745786683011426e-010, 1.444835156335356e-011,... +1.037067381285011e-012, 6.455906007234699e-014]; + +global gmsk_demod_coeff = [... +-0.000153959924563, 0.000000000000000, 0.000167227768379, 0.000341615513437,... +0.000513334449696, 0.000667493753523, 0.000783901543032, 0.000838293462576,... +0.000805143268199, 0.000661865814384, 0.000393913058926, -0.000000000000000,... +-0.000503471198655, -0.001079755887508, -0.001671728086040, -0.002205032425392,... +-0.002594597675000, -0.002754194565297, -0.002608210441859, -0.002104352817854,... +-0.001225654870420, 0.000000000000000, 0.001494548041184, 0.003130012785731,... +0.004735238379172, 0.006109242742194, 0.007040527007323, 0.007330850462455,... +0.006821247169795, 0.005417521811131, 0.003112202160626, -0.000000000000000,... +-0.003715739376345, -0.007727358782391, -0.011638713107503, -0.014992029537478,... +-0.017304097563429, -0.018108937286588, -0.017003180218569, -0.013689829477969,... +-0.008015928769710, 0.000000000000000, 0.010154104792614, 0.022059114281395,... +0.035162729807337, 0.048781621388364, 0.062148583345584, 0.074469032280094,... +0.084982001723750, 0.093020219991183, 0.098063819576269, 0.099782731268437,... +0.098063819576269, 0.093020219991183, 0.084982001723750, 0.074469032280094,... +0.062148583345584, 0.048781621388364, 0.035162729807337, 0.022059114281395,... +0.010154104792614, 0.000000000000000, -0.008015928769710, -0.013689829477969,... +-0.017003180218569, -0.018108937286588, -0.017304097563429, -0.014992029537478,... +-0.011638713107503, -0.007727358782391, -0.003715739376345, -0.000000000000000,... +0.003112202160626, 0.005417521811131, 0.006821247169795, 0.007330850462455,... +0.007040527007323, 0.006109242742194, 0.004735238379172, 0.003130012785731,... +0.001494548041184, 0.000000000000000, -0.001225654870420, -0.002104352817854,... +-0.002608210441859, -0.002754194565297, -0.002594597675000, -0.002205032425392,... +-0.001671728086040, -0.001079755887508, -0.000503471198655, -0.000000000000000,... +0.000393913058926, 0.000661865814384, 0.000805143268199, 0.000838293462576,... +0.000783901543032, 0.000667493753523, 0.000513334449696, 0.000341615513437,... +0.000167227768379, 0.000000000000000, -0.000153959924563]; + +rand('state',1); +randn('state',1); +graphics_toolkit ("gnuplot"); +fm; +close all; + +% +% Functions that implement the GMSK modem ------------------------------------------------------ +% + +function gmsk_states = gmsk_init(gmsk_states, Rs) + + % general + + verbose = gmsk_states.verbose; + gmsk_states.Fs = 48000; + gmsk_states.Rs = Rs; + M = gmsk_states.M = gmsk_states.Fs/gmsk_states.Rs; + global gmsk_mod_coeff; + global gmsk_demod_coeff; + gmsk_states.mod_coeff = (Rs/4800)*resample(gmsk_mod_coeff, 4800, Rs); + + if verbose > 1 + figure; + plot(gmsk_mod_coeff,'r;original 4800;') + hold on; + plot(gmsk_states.mod_coeff,'g;interpolated;') + hold off; + title('GMSK pulse shaping filter') + end + + % set up FM modulator + + fm_states.Fs = gmsk_states.Fs; + fm_states.fc = 0; + fm_max = fm_states.fm_max = Rs/2; + fd = fm_states.fd = Rs/4; + fm_states.Ts = gmsk_states.M; + fm_states.pre_emp = fm_states.de_emp = 0; + fm_states.output_filter = 1; + gmsk_states.fm_states = analog_fm_init(fm_states); + +endfunction + + +function [tx tx_filt tx_symbols] = gmsk_mod(gmsk_states, tx_bits) + M = gmsk_states.M; + nsym = length(tx_bits); + nsam = nsym*M; + verbose = gmsk_states.verbose; + + % NRZ sequence of symbols + + tx_symbols = zeros(1,nsam); + for i=1:nsym + tx_symbols(1+(i-1)*M:i*M) = -1 + 2*tx_bits(i); + end + + tx_filt = filter(gmsk_states.mod_coeff, 1, tx_symbols); + + if verbose > 1 + figure; + clf + plot(tx_filt(1:M*10)) + title('tx signal after filtering, before FM mod') + end + + tx = analog_fm_mod(gmsk_states.fm_states, tx_filt); +endfunction + + +function [rx_bits rx_int rx_filt] = gmsk_demod(gmsk_states, rx) + M = gmsk_states.M; + Rs = gmsk_states.Rs; + Fs = gmsk_states.Fs; + nsam = length(rx); + nsym = floor(nsam/M); + global gmsk_demod_coeff; + wd = 2*pi*gmsk_states.fm_states.fd/gmsk_states.Fs; + timing_angle_log = zeros(1,length(rx)); + rx_int = zeros(1,length(rx)); + + if gmsk_states.coherent_demod + + % See IEEE Trans on Comms, Muroyta et al, 1981, "GSM Modulation + % for Digital Radio Telephony" Fig 8: + + % matched filter + + rx_filt = filter(gmsk_states.mod_coeff, 1, rx); + + % Property of MSK that re and im arms are sequences of 2T + % long symbols, can be demodulated like QPSK with matched filter + % and integrate and dump. + + % integrate energy in symbols 2T long in re and im arms + % note this could be combined with matched filter + + rx_int = conv(rx_filt,ones(1,2*M)); + + % phase and fine frequency tracking and correction ------------------------ + + if gmsk_states.phase_track + + % DCO design from "Introduction To Phase-Lock Loop System Modeling", Wen Li + % http://www.ece.ualberta.ca/~ee401/parts/data/PLLIntro.pdf + + eta = 0.707; + wn = 2*pi*10*(Rs/4800); % (Rs/4800) -> found reducing the BW benifical with falling Rs + Ts = 1/Fs; + g1 = 1 - exp(-2*eta*wn*Ts); + g2 = 1 + exp(-2*eta*wn*Ts) - 2*exp(-eta*wn*Ts)*cos(wn*Ts*sqrt(1-eta*eta)); + Gpd = 2/pi; + Gvco = 1; + G1 = g1/(Gpd*Gvco); G2 = g2/(Gpd*Gvco); + %printf("g1: %e g2: %e G1: %e G2: %e\n", g1, g2, G1, G2); + + filt_prev = dco = lower = ph_err_filt = ph_err = 0; + dco_log = filt_log = zeros(1,nsam); + + % w is the ref sine wave at the timing clock frequency + % tw is the length of the window used to estimate timing + + k = 1; + tw = 200*M; + xr_log = []; xi_log = []; + w_log = []; + timing_clock_phase = 0; + timing_angle = 0; + timing_angle_log = zeros(1,nsam); + + for i=1:nsam + + % update sample timing estimate every tw samples + + if mod(i,tw) == 0 + l = i - tw+1; + xr = abs(real(rx_int(l:l+tw-1))); + xi = abs(imag(rx_int(l:l+tw-1))); + w = exp(j*(l:l+tw-1)*2*pi*(Rs/2)/Fs); + X = xr * w'; + timing_clock_phase = timing_angle = angle(X); + k++; + xr_log = [xr_log xr]; + xi_log = [xi_log xi]; + w_log = [w_log w]; + else + timing_clock_phase += (2*pi)/(2*M); + end + timing_angle_log(i) = timing_angle; + + rx_int(i) *= exp(-j*dco); + ph_err = sign(real(rx_int(i))*imag(rx_int(i)))*cos(timing_clock_phase); + lower = ph_err*G2 + lower; + filt = ph_err*G1 + lower; + dco = dco + filt; + filt_log(i) = filt; + dco_log(i) = dco; + end + + figure; + clf + subplot(211); + plot(filt_log); + title('PLL filter') + subplot(212); + plot(dco_log/pi); + title('PLL DCO phase'); + %axis([1 nsam -0.5 0.5]) + end + + % sample integrator output at correct timing instant + + timing_adj = timing_angle_log*2*M/(2*pi); + timing_adj_uw = unwrap(timing_angle_log)*2*M/(2*pi); + % Toff = floor(2*M+timing_adj); + Toff = floor(timing_adj_uw+0.5); + k = 1; + re_syms = im_syms = zeros(1,nsym/2); + + for i=2*M:2*M:nsam + if (i-Toff(i)+M) < nsam + re_syms(k) = real(rx_int(i-Toff(i))); + im_syms(k) = imag(rx_int(i-Toff(i)+M)); + end + %re_syms(k) = real(rx_int(i-10)); + %im_syms(k) = imag(rx_int(i+M-10)); + k++; + end + + figure + subplot(211) + stem(re_syms) + subplot(211) + stem(im_syms) + + figure; + clf + subplot(211) + plot(timing_adj); + title('Timing est'); + subplot(212) + plot(Toff); + title('Timing est unwrap'); + + % XORs/adders on the RHS of Muroyta et al Fig 8 (a) and (b). We + % simulate digital logic bit stream at clock rate Rs, even though + % we sample integrators at rate Rs/2. I can't explain how and why + % this logic works/is required. I think it can be worked out from + % comparing to MSK/OQPSK demod designs. + + l = length(re_syms); + l2 = 2*l; + re_bits = zeros(1,l2); + im_bits = zeros(1,l2); + clk_bits = zeros(1,l2); + for i=1:l-1 + re_bits(2*(i-1)+1) = re_syms(i) > 0; + re_bits(2*(i-1)+2) = re_syms(i) > 0; + im_bits(2*(i-1)+2) = im_syms(i) > 0; + im_bits(2*(i-1)+3) = im_syms(i) > 0; + clk_bits(2*(i-1)+1) = 0; + clk_bits(2*(i-1)+2) = 1; + end + + rx_bits = bitxor(bitxor(re_bits,im_bits), clk_bits); + rx_bits = rx_bits(2:length(rx_bits)-1); + else + % non-coherent demod + + % filter to get rid of most of noise before FM demod, but doesnt + % introduce any ISI + + fc = Rs/(Fs/2); + bin = firls(200,[0 fc*(1-0.05) fc*(1+0.05) 1],[1 1 0.01 0.01]); + rx_filt = filter(bin, 1, rx); + + % FM demod + + rx_diff = [ 1 rx_filt(2:nsam) .* conj(rx_filt(1:nsam-1))]; + rx_filt = (1/wd)*atan2(imag(rx_diff),real(rx_diff)); + + % low pass filter, trade off betwen ISI and removing noise + + rx_filt = filter(gmsk_demod_coeff, 1, rx_filt); + Toff = 7; + rx_bits = real(rx_filt(1+Toff:M:length(rx_filt)) > 0); + + end + +endfunction + + +% Initial frequency offset estimation. Look for line a centre +% frequency, which is the strongest component when ...101010... is +% used to modulate the GMSK signal. Note just searching for a single +% line will get false lock on random sine waves but that's OK for a +% PoC. It could be improved by checking for other lines, or +% demodulating the preamble and checking for bit errors. + +function [freq_offset_est ratio] = gmsk_est_freq_offset(gmsk_states, rx, verbose) + Fs = gmsk_states.Fs; + Rs = gmsk_states.Rs; + + % Suggest Rs/10 symbols of preamble (100ms), this works OK at + % Rs=4800 and Es/No = 6dB. The large, Fs sample FFT size is used + % for convenience (the bin resolution is 1 Hz), for real time we + % would decimate and use smaller FFT to save CPU and memory. + + ndft = Fs; + f = fft(rx .* hanning(length(rx))', ndft); + f = fftshift(f); + + start_bin = 1 + Fs/2-Rs/4; + stop_bin = start_bin + Rs/2; + [max_val max_bin] = max(abs(f(start_bin:stop_bin))); + + max_bin -= Rs/4 + 1; + if verbose > 1 + printf("ndft: %d start_bin: %d stop_bin: %d max_bin: %d\n", ndft, start_bin, stop_bin, max_bin); + end + + % calc ratio of line energy to total energy. For a valid preamble + % this was measured as about 0.20 to 0.25 depending on noise. + + sum_sq = sum(abs(f(start_bin:stop_bin)) .^ 2); + ratio = sqrt(max_val*max_val/sum_sq); + + % map max_bin to frequency offset + + freq_offset_est = max_bin; + + if verbose > 1 + printf("freq_offset_est: %f pk/rms ratio: %f \n", freq_offset_est, ratio); + figure; + clf + subplot(211) + plot(rx,'+') + title('rx signal on complex plane') + subplot(212) + plot(-Rs/4:Rs/4, 20*log10(abs(f(start_bin:stop_bin)))); + axis([-Rs/4 Rs/4 0 80]); + title('spectrum of rx signal'); + end + +endfunction + +% +% Functions for Testing the GMSK modem -------------------------------------------------------- +% + +function sim_out = gmsk_test(sim_in) + nsym = sim_in.nsym; + EbNodB = sim_in.EbNodB; + verbose = sim_in.verbose; + Rs = 4800; + + gmsk_states.verbose = verbose; + gmsk_states.coherent_demod = sim_in.coherent_demod; + gmsk_states.phase_track = 0; + gmsk_states = gmsk_init(gmsk_states, Rs); + M = gmsk_states.M; + Fs = gmsk_states.Fs; + Rs = gmsk_states.Rs; + Bfm = gmsk_states.fm_states.Bfm; + + for ne = 1:length(EbNodB) + aEbNodB = EbNodB(ne); + EbNo = 10^(aEbNodB/10); + variance = Fs/(Rs*EbNo); + + tx_bits = round(rand(1, nsym)); + %tx_bits = ones(1, nsym); + %tx_bits = zeros(1, nsym); + %tx_bits(1:2:nsym) = 0; + [tx tx_filt tx_symbols] = gmsk_mod(gmsk_states, tx_bits); + nsam = length(tx); + + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx*exp(j*pi/2) + noise; + + [rx_bits rx_out rx_filt] = gmsk_demod(gmsk_states, rx(1:length(rx))); + + % search for frame location over a range + + Nerrs_min = nsym; Nbits_min = nsym; l = length(rx_bits); + for i=1:100; + Nerrs = sum(xor(rx_bits(i:l), tx_bits(1:l-i+1))); + if Nerrs < Nerrs_min + Nerrs_min = Nerrs; + Nbits_min = l; + end + end + + TERvec(ne) = Nerrs_min; + BERvec(ne) = Nerrs_min/Nbits_min; + + if verbose > 0 + printf("EbNo dB: %3.1f Nerrs: %d BER: %f BER Theory: %f\n", aEbNodB, Nerrs_min, BERvec(ne), 0.5*erfc(sqrt(0.75*EbNo))); + end + + if verbose > 1 + + if gmsk_states.coherent_demod == 0 + Toff = 0; dsam = M*30; + figure; + clf + eyesyms = 2; + plot(rx_filt(dsam+1+Toff:dsam+eyesyms*M+Toff)) + hold on; + for i=1:10 + st = dsam+1+Toff+i*eyesyms*M; + en = st + eyesyms*M; + plot(rx_filt(st:en)) + end + hold off; + %axis([dsam dsam+eyesyms*M -2 2]); + title('Eye Diagram'); + else + figure; + nplot = 16; + clf; + subplot(211) + plot(real(rx_filt(1:nplot*M))) + axis([1 nplot*M -1 1]) + title('Matched Filter'); + subplot(212) + plot(imag(rx_filt(1:nplot*M))) + axis([1 nplot*M -1 1]) + + figure; + nplot = 16; + clf; + subplot(211) + plot(real(rx_out(1:nplot*M))/(2*M)) + title('Integrator'); + axis([1 nplot*M -1 1]) + subplot(212) + plot(imag(rx_out(1:nplot*M)/(2*M))) + axis([1 nplot*M -1 1]) + end + + figure; + clf + subplot(211) + stem(tx_bits(1:20)) + title('Tx Bits') + subplot(212) + stem(rx_bits(1:20)) + title('Rx Bits') + + figure; + clf + subplot(211); + f = fft(rx); + Tx = 20*log10(abs(f)); + plot(Tx) + grid; + title('GMSK Demodulator Input Spectrum'); + axis([1 5000 0 80]) + + subplot(212) + f = fft(tx); + f = f(1:length(f)/2); + cs = cumsum(abs(f).^2); + plot(cs) + hold on; + x = 0.99; + tots = x*sum(abs(f).^2); + xpercent_pwr = find(cs > tots); + bw = 2*xpercent_pwr(1); + plot([1 Fs/2],[tots tots],'r') + plot([bw/2 bw/2],[0 tots],'r') + hold off; + title("Cumulative Power"); + grid; + axis([1 5000 0 max(cs)]) + + printf("Bfm: %4.0fHz %3.0f%% power bandwidth %4.0fHz = %3.2f*Rb\n", Bfm, x*100, bw, bw/Rs); + + end + end + + sim_out.TERvec = TERvec; + sim_out.BERvec = BERvec; + sim_out.Rs = gmsk_states.Rs; +endfunction + + +function run_gmsk_single + sim_in.coherent_demod = 0; + sim_in.nsym = 4800; + sim_in.EbNodB = 10; + sim_in.verbose = 2; + + sim_out = gmsk_test(sim_in); +endfunction + + +% Generate a bunch of BER versus Eb/No curves for various demods + +function run_gmsk_curves + sim_in.coherent_demod = 1; + sim_in.nsym = 48000; + sim_in.EbNodB = 2:10; + sim_in.verbose = 1; + + gmsk_coh = gmsk_test(sim_in); + + sim_in.coherent_demod = 0; + gmsk_noncoh = gmsk_test(sim_in); + + Rs = gmsk_coh.Rs; + EbNo = 10 .^ (sim_in.EbNodB/10); + alpha = 0.75; % guess for BT=0.5 GMSK + gmsk_theory.BERvec = 0.5*erfc(sqrt(alpha*EbNo)); + + % BER v Eb/No curves + + figure; + clf; + semilogy(sim_in.EbNodB, gmsk_theory.BERvec,'r;GMSK theory;') + hold on; + semilogy(sim_in.EbNodB, gmsk_coh.BERvec,'g;GMSK sim coherent;') + semilogy(sim_in.EbNodB, gmsk_noncoh.BERvec,'b;GMSK sim non-coherent;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + + % BER v C/No (1 Hz noise BW and Eb=C/Rs=1/Rs) + % Eb/No = (C/Rs)/(1/(N/B)) + % C/N = (Eb/No)*(Rs/B) + + RsOnB_dB = 10*log10(Rs/1); + figure; + clf; + semilogy(sim_in.EbNodB+RsOnB_dB, gmsk_theory.BERvec,'r;GMSK theory;') + hold on; + semilogy(sim_in.EbNodB+RsOnB_dB, gmsk_coh.BERvec,'g;GMSK sim coherent;') + semilogy(sim_in.EbNodB+RsOnB_dB, gmsk_noncoh.BERvec,'b;GMSK sim non-coherent;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB+RsOnB_dB) max(sim_in.EbNodB+RsOnB_dB) 1E-4 1]) + legend("boxoff"); + xlabel("C/No for Rs=4800 bit/s and 1 Hz noise bandwidth (dB)"); + ylabel("Bit Error Rate (BER)") + +endfunction + + +function [preamble_location freq_offset_est] = find_preamble(gmsk_states, M, npreamble, rx) + verbose = gmsk_states.verbose; + + % look through rx buffer and determine if there is a valid preamble. Use steps of half the + % preamble size in samples to try to bracket the pre-amble. + + preamble_step = npreamble*M/2; + ratio = 0; freq_offset_est = 0; preamble_location = 0; + ratio_log = []; + for i=1:preamble_step:length(rx)-preamble_step + [afreq_offset_est aratio] = gmsk_est_freq_offset(gmsk_states, rx(i:i+preamble_step-1), verbose); + ratio_log = [ratio_log aratio]; + if aratio > ratio + preamble_location = i; + ratio = aratio; + freq_offset_est = afreq_offset_est; + end + end + if verbose + printf("preamble location: %2.1f seconds est f_off: %5.1f Hz ratio: %3.2f\n", + preamble_location/gmsk_states.Fs, freq_offset_est, ratio); + figure; + plot(ratio_log); + title('Preamble ratio'); + end +endfunction + + +% attempt to perform "coarse sync" sync with the received frames, we +% check each frame for the best coarse sync position. Brute force +% approach, that would be changed for a real demod which has some +% sort of unique word. Start looking for valid frames 1 frame +% after start of pre-amble to give PLL time to lock + +function [total_errors total_bits Nerrs_log Nerrs_all_log errors_log] = coarse_sync_ber(nframes_rx, tx_frame, rx_bits) + + Nerrs_log = zeros(1, nframes_rx); + Nerrs_all_log = zeros(1, nframes_rx); + total_errors = 0; + total_bits = 0; + framesize = length(tx_frame); + errors_log = []; + + for f=2:nframes_rx-1 + Nerrs_min = framesize; + for i=1:framesize; + st = (f-1)*framesize+i; en = st+framesize-1; + errors = xor(rx_bits(st:en), tx_frame); + Nerrs = sum(errors); + if Nerrs < Nerrs_min + Nerrs_min = Nerrs; + errors_min = errors; + end + end + Nerrs_all_log(f) = Nerrs_min; + if Nerrs_min/framesize < 0.1 + errors_log = [errors_log errors_min]; + Nerrs_log(f) = Nerrs_min; + total_errors += Nerrs_min; + total_bits += framesize; + end + end +endfunction + +function plot_spectrum(gmsk_states, rx, preamble_location, title_str) + Fs = gmsk_states.Fs; + st = preamble_location + gmsk_states.npreamble*gmsk_states.M; + sig = rx(st:st+Fs*0.5); + h = hanning(length(sig))'; + Rx=20*log10(abs(fftshift(fft(sig .* h, Fs)))); + figure; + plot(-Fs/2:Fs/2-1,Rx); + grid("minor"); + xlabel('Hz'); + ylabel('dB'); + topy = ceil(max(Rx)/10)*10; + axis([-4000 4000 topy-50 topy+10]) + title(title_str); +endfunction + +% Give the demod a hard time: frequency, phase, time offsets, sample clock difference + +function run_test_channel_impairments + Rs = 1200; + verbose = 1; + aEbNodB = 6; + phase_offset = pi/2; + freq_offset = -104; + timing_offset = 100E3; + sample_clock_offset_ppm = -500; + interferer_freq = -1500; + interferer_amp = 0; + nsym = 4800*2; + npreamble = 480; + + gmsk_states.npreamble = npreamble; + gmsk_states.verbose = verbose; + gmsk_states.coherent_demod = 1; + gmsk_states.phase_track = 1; + gmsk_states = gmsk_init(gmsk_states, Rs); + Fs = gmsk_states.Fs; + Rs = gmsk_states.Rs; + M = gmsk_states.M; + + % A frame consists of nsym random data bits. Some experimentation + % has shown they must be random-ish data (not say 11001100...) for + % timing estimator to work. However initial freq offset estimation + % is a lot easier with a 01010 type sequence, so we construct a + % frame with a pre-amble followed by frames of random data. + + framesize = 480; + nframes = floor(nsym/framesize); + tx_frame = round(rand(1, framesize)); + tx_bits = zeros(1,npreamble); + tx_bits(1:2:npreamble) = 1; + for i=1:nframes + tx_bits = [tx_bits tx_frame]; + end + + [tx tx_filt tx_symbols] = gmsk_mod(gmsk_states, tx_bits); + + tx = resample(tx, 1E6, 1E6-sample_clock_offset_ppm); + tx = [zeros(1,timing_offset) tx]; + nsam = length(tx); + + if verbose > 1 + figure; + subplot(211) + st = timing_offset; en = st+M*10; + plot(real(tx(st:en))) + title('Real part of tx'); + subplot(212) + plot(imag(tx(st:en))) + title('Imag part of tx'); + end + + EbNo = 10^(aEbNodB/10); + variance = Fs/(Rs*EbNo); + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + w = (0:nsam-1)*2*pi*freq_offset/Fs + phase_offset; + interferer = interferer_amp*exp(j*interferer_freq*(2*pi/Fs)*(0:nsam-1)); + + rx = sqrt(2)*tx.*exp(j*w) + noise + interferer; + + % optional dump to file + + if 1 + fc = 1500; gain = 10000; + wc = 2*pi*fc/Fs; + w1 = exp(j*wc*(1:nsam)); + rx1 = gain*real(rx .* w1); + fout = fopen("rx_6dB.raw","wb"); + fwrite(fout, rx1, "short"); + fclose(fout); + end + + rx = rx1 .* conj(w1); + + [preamble_location freq_offset_est] = find_preamble(gmsk_states, M, npreamble, rx); + w_est = (0:nsam-1)*2*pi*freq_offset_est/Fs; + rx = rx.*exp(-j*w_est); + + plot_spectrum(gmsk_states, rx, preamble_location, "GMSK rx just after preamble"); + + % printf("ntx: %d nrx: %d ntx_bits: %d\n", length(tx), length(rx), length(tx_bits)); + + [rx_bits rx_out rx_filt] = gmsk_demod(gmsk_states, rx(preamble_location+framesize:nsam)); + nframes_rx = length(rx_bits)/framesize; + + % printf("ntx: %d nrx: %d ntx_bits: %d nrx_bits: %d\n", length(tx), length(rx), length(tx_bits), length(rx_bits)); + + [total_errors total_bits Nerrs_log Nerrs_all_log] = coarse_sync_ber(nframes_rx, tx_frame, rx_bits); + + ber = total_errors/total_bits; + + printf("Eb/No: %3.1f f_off: %4.1f ph_off: %4.3f Nframes: %d Nbits: %d Nerrs: %d BER: %f\n", + aEbNodB, freq_offset, phase_offset, nframes_rx, total_bits, total_errors, ber); + + figure; + clf + subplot(211) + plot(Nerrs_log,'r;errors/frame counted for BER;'); + hold on; + plot(Nerrs_all_log,'g;all errors/frame;'); + hold off; + legend("boxoff"); + title('Bit Errors') + subplot(212) + stem(real(cumsum(Nerrs_log))) + title('Cumulative Bit Errors') + +endfunction + + +% Generates a Fs=48kHz raw file of 16 bit samples centred on 1500Hz, +% Suitable for transmitting with a SSB tx + +function gmsk_tx(tx_file_name) + rand('state',1); + Rs = 1200; + nsym = Rs*4; + framesize = 480; + npreamble = 480; + gain = 10000; + fc = 1500; + + gmsk_states.verbose = 0; + gmsk_states.coherent_demod = 1; + gmsk_states.phase_track = 1; + gmsk_states = gmsk_init(gmsk_states, Rs); + Fs = gmsk_states.Fs; + Rs = gmsk_states.Rs; + M = gmsk_states.M; + + % generate frame with preamble + + nframes = floor(nsym/framesize) + tx_frame = round(rand(1, framesize)); + tx_bits = zeros(1,npreamble); + tx_bits(1:2:npreamble) = 1; + for i=1:nframes + tx_bits = [tx_bits tx_frame]; + end + + [tx tx_filt tx_symbols] = gmsk_mod(gmsk_states, tx_bits); + nsam = length(tx); + + wc = 2*pi*fc/Fs; + w = exp(j*wc*(1:nsam)); + tx = gain*real(tx .* w); + figure; + plot(tx(1:4000)) + fout = fopen(tx_file_name,"wb"); + fwrite(fout, tx, "short"); + fclose(fout); + +endfunction + + +% Reads a file of Fs=48kHz 16 bit samples centred on 1500Hz, and +% measures the BER. + +function gmsk_rx(rx_file_name, err_file_name) + rand('state',1); + + Rs = 1200; + framesize = 480; + npreamble = 480; + fc = 1500; + + gmsk_states.npreamble = npreamble; + gmsk_states.verbose = 1; + gmsk_states.coherent_demod = 1; + gmsk_states.phase_track = 1; + gmsk_states = gmsk_init(gmsk_states, Rs); + Fs = gmsk_states.Fs; + Rs = gmsk_states.Rs; + M = gmsk_states.M; + + tx_frame = round(rand(1, framesize)); + + % get real signal at fc offset and convert to baseband complex + % signal + + fin = fopen(rx_file_name,"rb"); + rx = fread(fin,"short")'; + fclose(fin); + rx = filter([1 -0.999],[1 -0.99],rx); + nsam = length(rx); + wc = 2*pi*fc/Fs; + w = exp(-j*wc*(1:nsam)); + rxbb = rx .* w; + + figure; + plot(rx); + + % find preamble + + [preamble_location freq_offset_est] = find_preamble(gmsk_states, M, npreamble, rxbb); + + % power of signal, averaged over window + % TODO: remove wave file header, scale of actual level + % filter so we measure only energy in our passband + % work out noise BW of filter. Use GMSK filter? + + [b a] = cheby2(6,40,[200 3000]/(Fs/2)); + %bpwr_lp = fir2([200,4000/(Fs/2)); + noise_bw = var(filter(b,a,randn(1,1E6))); + + rx_filt = filter(b, a, rx(1000:length(rx))); + npower_window = 200*M; + rx_power = conv(rx_filt.^2,ones(1,npower_window))/(npower_window); + rx_power_dB = 10*log10(rx_power); + figure; + subplot(211) + plot(rx_filt(1000:length(rx_filt))); + title('GMSK Power (narrow filter)'); + subplot(212) + plot(rx_power_dB); + axis([1 length(rx_power) max(rx_power_dB)-29 max(rx_power_dB)+1]) + grid("minor") + + % Work out where to sample N, and S+N + + noise_end = preamble_location - 2*npreamble*M; + noise_start = noise_end - Fs; + if noise_start < 1 + printf("Hmm, we really need >1 second of noise only before preamble to measure noise!\n"); + else + noise = mean(rx_power_dB(noise_start:noise_end)); + signal_noise_start = preamble_location + 2*npreamble*M; + signal_noise_end = signal_noise_start + Fs; + signal_noise = mean(rx_power_dB(signal_noise_start:signal_noise_end)); + hold on; + plot([noise_start noise_end],[noise noise],'color','r','linewidth',5); + plot([signal_noise_start signal_noise_end],[signal_noise signal_noise],'color','r','linewidth',5); + + % determine SNR + + noise_lin = 10 ^ (noise/10); + signal_noise_lin = 10 ^ (signal_noise/10); + signal_lin = signal_noise_lin - noise_lin; + signal = 10*log10(signal_lin); + snr = signal - noise; + fudge_factor = 3; % 3dB for single/double sided noise adjustment? Just a guess + CNo = snr + 10*log10(Fs*noise_bw) - fudge_factor; + EbNo = CNo - 10*log10(Rs); + + EbNo_lin = 10 .^ (EbNo/10); + alpha = 0.75; % guess for BT=0.5 GMSK + ber_theory = 0.5*erfc(sqrt(alpha*EbNo_lin)); + + printf("Estimated S: %3.1f N: %3.1f Nbw: %4.0f Hz SNR: %3.1f CNo: %3.1f EbNo: %3.1f BER theory: %f\n", + signal, noise, Fs*noise_bw, snr, CNo, EbNo, ber_theory); + + % FM signal is centred on 12 kHz and 16 kHz wide so lets also work out noise there + + [b a] = cheby2(6,40,[12000-8000 12000+8000]/(Fs/2)); + noise_bw_fm = var(filter(b,a,randn(1,1E6))); + + rx_filt_fm = filter(b, a, rx(1000:length(rx))); + rx_power_fm = conv(rx_filt_fm.^2,ones(1,npower_window))/(npower_window); + rx_power_dB_fm = 10*log10(rx_power_fm); + + noise = mean(rx_power_dB_fm(noise_start:noise_end))*ones(1, length(rx_power_fm)); + noise_lin = 10 .^ (noise/10); + + signal_lin = rx_power_fm - noise_lin; + signal = 10*log10(abs(signal_lin) + 1E-6); + snr = signal - noise; + + CNo = snr + 10*log10(Fs*noise_bw_fm) - fudge_factor; + + figure + plot(rx_power_dB_fm,'r;signal plus noise;'); + hold on; + plot(CNo,'g;C/No;'); + hold off; + top_fm = ceil(max(CNo)/10)*10; + axis([1 length(rx_power_dB_fm) 20 top_fm]) + grid("minor") + legend("boxoff"); + title('FM C/No'); + end + + % spectrum of a chunk of GMSK signal just after preamble + + plot_spectrum(gmsk_states, rx, preamble_location, "GMSK rx just after preamble"); + + % correct freq offset and demodulate + + w_est = (0:nsam-1)*2*pi*freq_offset_est/Fs; + rxbb = rxbb.*exp(-j*w_est); + st = preamble_location+npreamble*M; + %en = min(nsam,st + 4*framesize*M); + en = nsam; + gmsk_statres.verbose = 2; + [rx_bits rx_out rx_filt] = gmsk_demod(gmsk_states, rxbb(st:en)); + nframes_rx = length(rx_bits)/framesize; + + % count errors + + [total_errors total_bits Nerrs_log Nerrs_all_log errors_log] = coarse_sync_ber(nframes_rx, tx_frame, rx_bits); + + ber = total_errors/total_bits; + + printf("Nframes: %d Nbits: %d Nerrs: %d BER: %f\n", + nframes_rx, total_bits, total_errors, ber); + + % Optionally save a file of bit errors so we can simulate the effect on Codec 2 + + if nargin == 2 + + % To simulate effects of these errors on Codec 2: + % $ ~/codec2-dev/octave$ ../build_linux/src/c2enc 1300 ../raw/hts1raw - | ../build_linux/src/insert_errors - - ssb7dbSNR.err 52 | ../build_linux/src/c2dec 1300 - - | play -t raw -r 8000 -s -2 - + % Note in this example I'm using the 1300 bit/s codec, it's sig more robust that 1200 bit/s, + % if we ran the GMSK modem at 1300 bit/s there would be a 10*log10(1300/1200) = 0.35dB SNR penalty + + fep=fopen(err_file_name,"wb"); fwrite(fep, errors_log, "short"); fclose(fep); + end + + figure; + clf + subplot(211) + plot(Nerrs_log,'r;errors/frame counted for BER;'); + hold on; + plot(Nerrs_all_log,'g;all errors/frame;'); + hold on; + title('Bit Errors') + legend("boxoff"); + subplot(212) + stem(real(cumsum(Nerrs_log))) + title('Cumulative Bit Errors') +endfunction + + +%run_gmsk_single +%run_gmsk_curves +%run_gmsk_init +%run_test_channel_impairments +gmsk_tx("test_gmsk.raw") +gmsk_rx("test_gmsk.raw") +%gmsk_rx("ssb25db.wav") +%gmsk_rx("~/Desktop/ssb_fm_gmsk_high.wav") +%gmsk_rx("~/Desktop/test_gmsk_28BER.raw") +%gmsk_rx("~/Desktop/gmsk_rec_reverse.wav") + diff --git a/codec2/branches/0.7/octave/gp_interleaver.m b/codec2/branches/0.7/octave/gp_interleaver.m new file mode 100644 index 00000000..1ee0ee38 --- /dev/null +++ b/codec2/branches/0.7/octave/gp_interleaver.m @@ -0,0 +1,46 @@ +% gp_interleaver.m +% +% David Rowe May 2017 +% +% Golden Prime Interleaver. My interprestation of "On the Analysis and +% Design of Good Algebraic Interleavers", Xie et al,eq (5). + +1; + +% Choose b for Golden Prime Interleaver. b is chosen to be the +% closest integer, which is relatively prime to N, to the Golden +% section of N. + +function b = choose_interleaver_b(Nbits) + + p = primes(Nbits); + i = 1; + while(p(i) < Nbits/1.62) + i++; + end + b = p(i); + assert(gcd(b,Nbits) == 1, "b and Nbits must be co-prime"); +end + + +function interleaved_frame = gp_interleave(frame) + Nbits = length(frame); + b = choose_interleaver_b(Nbits); + interleaved_frame = zeros(1,Nbits); + for i=1:Nbits + j = mod((b*(i-1)), Nbits); + interleaved_frame(j+1) = frame(i); + end +endfunction + + +function frame = gp_deinterleave(interleaved_frame) + Nbits = length(interleaved_frame); + b = choose_interleaver_b(Nbits); + frame = zeros(1,Nbits); + for i=1:Nbits + j = mod((b*(i-1)), Nbits); + frame(i) = interleaved_frame(j+1); + end +endfunction + diff --git a/codec2/branches/0.7/octave/hackrf_dc.m b/codec2/branches/0.7/octave/hackrf_dc.m new file mode 100644 index 00000000..a204e70c --- /dev/null +++ b/codec2/branches/0.7/octave/hackrf_dc.m @@ -0,0 +1,26 @@ +% hackrf_dc.m +% +% David Rowe Nov 2015 +% +% Downconverts a HackRF IQ sample file to a lower sample rate +% +% To sample a -60dB signal: +% $ hackrf_transfer -r df1.iq -f 439200000 -n 10000000 -l 20 -g 40play file at 10.7MHz used: +% octave:25> d = hackrf_dc("df1.iq") + +function d = hackrf_dc(infilename) + Fs1 = 10E6; % input sample rate to HackRF + Fs2 = 96E3; % output sample rate + fc = 700E3; % offset to shift input by, HackRF doesn't like signals in the centre + + s1 = load_hackrf(infilename); + ls1 = length(s1); + ls1 = 20*Fs1; + t = 0:ls1-1; + + % shift down to baseband from Fc, not sure of rot90 rather than trasnpose operator ' + % to avoid unwanted complex conj + + s2 = rot90(s1(1:ls1)) .* exp(-j*2*pi*t*fc/Fs1); + d = resample(s2, Fs2, Fs1); +end diff --git a/codec2/branches/0.7/octave/hackrf_twotone.m b/codec2/branches/0.7/octave/hackrf_twotone.m new file mode 100644 index 00000000..1d5aa025 --- /dev/null +++ b/codec2/branches/0.7/octave/hackrf_twotone.m @@ -0,0 +1,24 @@ +% hackrf_twotone.m +% +% David Rowe Nov 2015 +% +% Generates a two tone test signal that can be played out of HackRF +% +% To play file at 10.7MHz used: +% $ hackrf_transfer -t ../octave/twotone.iq -f 10000000 -a 0 -x 47 +% +% However 2nd harmonic at 21.4 was only -32dBC so not really useful for my application +% in testing an ADC + +Fs = 8E6; +fc = 2E6; +f1 = fc; +f2 = fc+1E3; +A = 127; +T = 2; + +N = T*Fs; +t = 0:N-1; +%s = A*exp(j*2*pi*t*f1/Fs) + A*exp(j*2*pi*t*f2/Fs); +s = A*exp(j*2*pi*t*f2/Fs); +save_hackrf("twotone.iq",s); diff --git a/codec2/branches/0.7/octave/hackrf_uc.m b/codec2/branches/0.7/octave/hackrf_uc.m new file mode 100644 index 00000000..0f55bd1b --- /dev/null +++ b/codec2/branches/0.7/octave/hackrf_uc.m @@ -0,0 +1,47 @@ +% hackrf_uc.m +% +% David Rowe Nov 2015 +% +% Upconverts a real baseband sample file to a file suitable for input into a HackRF +% +% To play file at 10.7MHz used: +% octave:25> hackrf_uc("fsk_10M.iq","fsk_horus_rx_1200_96k.raw") +% $ hackrf_transfer -t ../octave/fsk_10M.iq -f 10000000 -a 1 -x 40 + +function hackrf_uc(outfilename, infilename) + pkg load signal; + Fs1 = 48E3; % input sample rate + Fs2 = 10E6; % output sample rate to HackRF + fc = 700E3-24E3; % offset to shift to, HackRF doesn't like signals in the centre + A = 100; % amplitude of signal after upc-nversion (max 127) + N = Fs1*20; + + fin = fopen(infilename,"rb"); + printf("1\n"); + s1 = fread(fin,"short"); + printf("1\n"); + fclose(fin); + printf("1\n"); + ls1 = length(s1); + printf("1\n"); + N = ls1; + % single sided freq shifts, we don't want DSB + printf("1\n"); + s1 = hilbert(s1(1:N)); + + % upsample to Fs2 + + M = Fs2/Fs1; + s2 = resample(s1(1:N),Fs2,Fs1); + ls2 = length(s2); + mx = max(abs(s2)); + t = 0:ls2-1; + printf("2\n"); + % shift up to Fc, note use of rot90 rather than trasnpose operator ' + % as we don't want complex conj, that would shift down in freq + + sout = rot90((A/mx)*s2) .* exp(j*2*pi*t*fc/Fs2); + + save_hackrf(outfilename,sout); + +end diff --git a/codec2/branches/0.7/octave/hf_modem_curves.m b/codec2/branches/0.7/octave/hf_modem_curves.m new file mode 100644 index 00000000..094802e2 --- /dev/null +++ b/codec2/branches/0.7/octave/hf_modem_curves.m @@ -0,0 +1,272 @@ +% hf_modem_curves +% David Rowe Feb 2017 +% +% Ideal implementations of a bunch of different HF modems, used to +% generate plots for a blog post. + +#{ + [X] ideal AWGN/HF curves + [X] exp AWGN QPSK curves + [X] exp AWGN DQPSK curves + [X] exp HF channel model + [ ] diversity + [ ] COHPSK frames + + would require multiple carriers + + filtering or OFDM +#} + +1; + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +% Rate Rs modem simulation model ------------------------------------------------------- + +function sim_out = ber_test(sim_in) + bps = 2; % two bits/symbol for QPSK + Rs = 50; % symbol rate (needed for HF model) + + verbose = sim_in.verbose; + EbNovec = sim_in.EbNovec; + hf_en = sim_in.hf_en; + + % user can supply number of bits per point to get good results + % at high Eb/No + + if length(sim_in.nbits) > 1 + nbitsvec = sim_in.nbits; + nbitsvec += 100 - mod(nbitsvec,100); % round up to nearest 100 + else + nbitsvec(1:length(EbNovec)) = sim_in.nbits; + end + + % init HF model + + if hf_en + + % some typical values + + dopplerSpreadHz = 1.0; path_delay = 1E-3*Rs; + + nsymb = max(nbitsvec)/2; + spread1 = doppler_spread(dopplerSpreadHz, Rs, nsymb); + spread2 = doppler_spread(dopplerSpreadHz, Rs, nsymb); + hf_gain = 1.0/sqrt(var(spread1)+var(spread2)); + % printf("nsymb: %d lspread1: %d\n", nsymb, length(spread1)); + end + + for ne = 1:length(EbNovec) + + % work out noise power ------------- + + EbNodB = EbNovec(ne); + EsNodB = EbNodB + 10*log10(bps); + EsNo = 10^(EsNodB/10); + variance = 1/EsNo; + nbits = nbitsvec(ne); + nsymb = nbits/bps; + + % modulator ------------------------ + + tx_bits = rand(1,nbits) > 0.5; + tx_symb = []; + prev_tx_symb = 1; + for s=1:nsymb + atx_symb = qpsk_mod(tx_bits(2*s-1:2*s)); + if sim_in.dqpsk + atx_symb *= prev_tx_symb; + prev_tx_symb = atx_symb; + end + tx_symb = [tx_symb atx_symb]; + end + + % channel --------------------------- + + rx_symb = tx_symb; + + if hf_en + + % simplified rate Rs simulation model that doesn't include + % ISI, just freq filtering. We assume perfect phase estimation + % so it's just amplitude distortion. + + hf_model1 = hf_model2 = zeros(1, nsymb); + for s=1:nsymb + hf_model1(s) = hf_gain*(spread1(s) + exp(-j*path_delay)*spread2(s)); + hf_model = abs(hf_model1(s)); + + if sim_in.diversity + % include amplitude information from another frequency in channel model + w1 = 7*2*pi; + hf_model2(s) = hf_gain*(spread1(s) + exp(-j*w1*path_delay)*spread2(s)); + hf_model = 0.5*abs(hf_model1(s)) + 0.5*abs(hf_model2(s)); + end + + rx_symb(s) = rx_symb(s).*hf_model; + end + end + + % variance is noise power, which is divided equally between real and + % imag components of noise + + noise = sqrt(variance*0.5)*(randn(1,nsymb) + j*randn(1,nsymb)); + rx_symb += noise; + + % demodulator ------------------------------------------ + + % demodulate rx symbols to bits + + rx_bits = []; + prev_rx_symb = 1; + for s=1:nsymb + arx_symb = rx_symb(s); + if sim_in.dqpsk + tmp = arx_symb; + arx_symb *= prev_rx_symb'; + prev_rx_symb = tmp; + end + two_bits = qpsk_demod(arx_symb); + rx_bits = [rx_bits two_bits]; + end + + % count errors ----------------------------------------- + + error_pattern = xor(tx_bits, rx_bits); + nerrors = sum(error_pattern); + bervec(ne) = nerrors/nbits; + if verbose + printf("EbNodB: % 3.1f nbits: %5d nerrors: %5d ber: %4.3f\n", EbNodB, nbits, nerrors, bervec(ne)); + if verbose == 2 + figure(2); clf; + plot(rx_symb*exp(j*pi/4),'+','markersize', 10); + mx = max(abs(rx_symb)); + axis([-mx mx -mx mx]); + if sim_in.diversity && sim_in.hf_en + figure(3); + plot(1:nsymb, abs(hf_model1), 1:nsymb, abs(hf_model2), 'linewidth', 2); + end + end + end + end + + sim_out.bervec = bervec; +endfunction + + +% ------------------------------------------------------------- + + +function run_single + sim_in.verbose = 2; + sim_in.nbits = 1000; + sim_in.EbNovec = 4; + sim_in.dqpsk = 0; + sim_in.hf_en = 0; + sim_in.diversity = 0; + + sim_qpsk = ber_test(sim_in); +endfunction + + +function run_curves + max_nbits = 1E5; + sim_in.verbose = 1; + sim_in.EbNovec = 0:10; + sim_in.dqpsk = 0; + sim_in.hf_en = 0; + sim_in.diversity = 0; + + % AWGN ----------------------------- + + ber_awgn_theory = 0.5*erfc(sqrt(10.^(sim_in.EbNovec/10))); + sim_in.nbits = min(max_nbits, floor(500 ./ ber_awgn_theory)); + + sim_qpsk = ber_test(sim_in); + sim_in.dqpsk = 1; + sim_dqpsk = ber_test(sim_in); + + % HF ----------------------------- + + hf_sim_in = sim_in; hf_sim_in.dqpsk = 0; hf_sim_in.hf_en = 1; + hf_sim_in.EbNovec = 0:16; + + EbNoLin = 10.^(hf_sim_in.EbNovec/10); + ber_hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + hf_sim_in.nbits = min(max_nbits, floor(500 ./ ber_hf_theory)); + sim_qpsk_hf = ber_test(hf_sim_in); + + hf_sim_in.dqpsk = 1; + sim_dqpsk_hf = ber_test(hf_sim_in); + + hf_sim_in.dqpsk = 0; + hf_sim_in.diversity = 1; + sim_qpsk_hf_div = ber_test(hf_sim_in); + + % Plot results -------------------- + + close all; + figure (1, 'position', [100, 10, 600, 400]); clf; + + semilogy(sim_in.EbNovec, ber_awgn_theory,'r+-;QPSK AWGN theory;', 'linewidth', 2) + xlabel('Eb/No (dB)') + ylabel('BER') + grid("minor") + axis([min(sim_in.EbNovec) max(sim_in.EbNovec) 1E-3 1]) + hold on; + + semilogy([0 4 4], [ber_awgn_theory(5) ber_awgn_theory(5) 1E-3],'k--', 'linewidth', 2); + hold off; + + figure (2, 'position', [300, 10, 600, 400]); clf; + semilogy(sim_in.EbNovec, ber_awgn_theory,'r+-;QPSK AWGN theory;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(sim_in.EbNovec, sim_qpsk.bervec,'g+-;QPSK AWGN simulated;','markersize', 10, 'linewidth', 2) + semilogy(sim_in.EbNovec, sim_dqpsk.bervec,'b+-;DQPSK AWGN simulated;','markersize', 10, 'linewidth', 2) + xlabel('Eb/No (dB)') + ylabel('BER') + grid("minor") + axis([min(sim_in.EbNovec) max(sim_in.EbNovec) 1E-3 1]) + + figure (3, 'position', [400, 10, 600, 400]); clf; + semilogy(sim_in.EbNovec, ber_awgn_theory,'r+-;QPSK AWGN theory;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(sim_in.EbNovec, sim_qpsk.bervec,'g+-;QPSK AWGN simulated;','markersize', 10, 'linewidth', 2) + semilogy(sim_in.EbNovec, sim_dqpsk.bervec,'b+-;DQPSK AWGN simulated;','markersize', 10, 'linewidth', 2) + semilogy(hf_sim_in.EbNovec, ber_hf_theory,'r+-;QPSK HF theory;','markersize', 10, 'linewidth', 2) + semilogy(hf_sim_in.EbNovec, sim_dqpsk_hf.bervec,'b+-;DQPSK HF simulated;','markersize', 10, 'linewidth', 2) + semilogy(hf_sim_in.EbNovec, sim_qpsk_hf.bervec,'g+-;QPSK HF simulated;','markersize', 10, 'linewidth', 2) + semilogy(hf_sim_in.EbNovec, sim_qpsk_hf_div.bervec,'c+-;QPSK Diversity HF simulated;','markersize', 10, 'linewidth', 2) + hold off; + xlabel('Eb/No (dB)') + ylabel('BER') + grid("minor") + axis([min(hf_sim_in.EbNovec) max(hf_sim_in.EbNovec) 1E-3 1]) + +endfunction + +% ------------------------------------------------------------- + +more off; +rand('seed',1); randn('seed', 1); +%run_curves +run_single diff --git a/codec2/branches/0.7/octave/hf_sim.m b/codec2/branches/0.7/octave/hf_sim.m new file mode 100644 index 00000000..c9105c00 --- /dev/null +++ b/codec2/branches/0.7/octave/hf_sim.m @@ -0,0 +1,78 @@ +% hf_sim.m +% David Rowe March 2014 +% +% Two path CCIR poor HF channel simulation, with apaologies to PathSim + +% Init HF channel model from stored sample files of spreading signal ---------------------------------- + +global spread; +global spread_2ms; +global hf_gain; + +% convert "spreading" samples from 1kHz carrier at Fs to complex +% baseband, generated by passing a 1kHz sine wave through PathSim with +% the ccir-poor model, enabling one path at a time. Because I'm too +% lazy to generate my own spreading signals + +Fc = 1000; Fs=8000; +fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); +spread1k = fread(fspread, "int16")/10000; +fclose(fspread); +fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); +spread1k_2ms = fread(fspread, "int16")/10000; +fclose(fspread); + +% down convert to complex baseband + +spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); +spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + +% remove -2000 Hz image + +b = fir1(50, 5/Fs); +spread = filter(b,1,spreadbb); +spread_2ms = filter(b,1,spreadbb_2ms); + +% discard first 1000 samples as these were near 0, probably as +% PathSim states were ramping up + +spread = spread(1000:length(spread)); +spread_2ms = spread_2ms(1000:length(spread_2ms)); + +hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + +% This function simulates the HF channel at 8kHz for real signals. A +% good use case is passing a vector of speech samples through it to +% simulate SSB over HF. There's a really good reason for the 300 - +% 3000 Hz filter that escapes me right now :-) + +function [sim_out snr3kHz_measured ] = hf_sim_real(sim_in, snr3kHz) + + % 300 - 3000 Hz filter + + b = fir1(100,[300/4000, 3000/4000], 'pass'); + + % det power of unit variance noise passed through this filter + + filter_var = var(filter(b,1,randn(1000,1))); + + % Start simulation + + s = hilbert(filter(b,1,sim_in)); + n1 = length(s); n2 = length(spread); + n = min(n1,n2); + path1 = s(1:n) .* spread(1:n); + path2 = s(1:n) .* spread_2ms(1:n); + delay = floor(0.002*Fs); + + combined = path1(delay+1:n) + path2(1:n-delay); + + snr = 10 .^ (snr3kHz/10); + variance = (combined'*combined)/(snr*n); + noise = sqrt(variance*0.5/filter_var)*(randn(n-delay,1) + j*randn(n-delay,1)); + filtered_noise = filter(b,1,noise); + + sim_out = real(combined+filtered_noise); + snr3kHz_measured = 10*log10(var(real(combined))/var(real(filtered_noise))); +endfunction + diff --git a/codec2/branches/0.7/octave/hfper.m b/codec2/branches/0.7/octave/hfper.m new file mode 100644 index 00000000..b3396342 --- /dev/null +++ b/codec2/branches/0.7/octave/hfper.m @@ -0,0 +1,57 @@ +% hfper.m +% David Rowe 2 June 2014 +% Quick and dirty HF PER calculator/simulator + +function hfper(ber, nbits, ntrials) + + % Raw PER with no FEC -------------------------------------- + + nper = 0; + for i=1:ntrials + nerr = sum(rand(1,nbits) < ber); + if nerr >0 + nper++; + end + end + printf("Raw PER..................: %0.3f\n", nper/ntrials); + + % Half rate block code, e.g. Golay (23,12) with 3 bit error + % correcting capability + + % Golay (23,12) that can correct 3 errors (fails at 4) ------ + + ncodeword = 23; + ncorrect = 3; + nper = 0; + for i=1:ntrials + nerr = sum(rand(1,ncodeword) < ber); + if nerr > ncorrect + nper++; + end + end + printf("One Golay codeword.......: %0.3f\n", nper/ntrials); + + % Several Golay codewords concatenated ---------------------- + + m = floor(nbits/12); % number of codewords + + nper = 0; + for i=1:ntrials + + % test each codeword in packet, if any of the codewords has > 4 + % errors, entire packet is a dud + + no_errors = 1; + for k=1:m + nerr = sum(rand(1,ncodeword) < ber); + if (nerr > ncorrect) && no_errors + nper++; + no_errors = 0; + end + end + + end + printf("Packet protected by Golay: %0.3f\n", nper/ntrials); + +endfunction + diff --git a/codec2/branches/0.7/octave/horus_high_speed.bin b/codec2/branches/0.7/octave/horus_high_speed.bin new file mode 100644 index 0000000000000000000000000000000000000000..8d5b1f366f415996a180e4ffd0455fd24633276f GIT binary patch literal 2760 zcmd6jiE+a~3& z+Neh5X^hXycZ|A>;AQ1y|Mz*yPwW5vsg*8y0+}XTp1UIi5aq*S( z`^9%dkyhiI2E7- z`-WexWa^@^F4pB2SG7b~v=O%YN=WsUT+k{dAU;VPN$mD~c(r@a>|%_s#93d-b`3Ow z4(2P-@6**ZE1Q|#IbVr!c1MmoJt01^NxO$hxz;4jA0IYp6vRwkD2QfJhfuy!#_~<$ zi!?8EO0|(J@j3o1RI)ZwrTFd;>4SI!{cUkrB zNDJ0@#^(!K1ir=;8VTFBFTn@@@ImFUM63JcLQ+K9XAE3sK$iL<^Ei}jUw rudj4@l87jQ)Wcl5v)YJpeWixndsaDZ<0y5APZ_()_g3@td-44NutWuG literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/octave/horus_msg.txt b/codec2/branches/0.7/octave/horus_msg.txt new file mode 100644 index 00000000..882a9b3a --- /dev/null +++ b/codec2/branches/0.7/octave/horus_msg.txt @@ -0,0 +1 @@ + 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 diff --git a/codec2/branches/0.7/octave/horus_payload_rtty.txt b/codec2/branches/0.7/octave/horus_payload_rtty.txt new file mode 100644 index 00000000..882a9b3a --- /dev/null +++ b/codec2/branches/0.7/octave/horus_payload_rtty.txt @@ -0,0 +1 @@ + 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 1.00000000e+00 0.00000000e+00 diff --git a/codec2/branches/0.7/octave/horus_tx_bits_binary.txt b/codec2/branches/0.7/octave/horus_tx_bits_binary.txt new file mode 100644 index 00000000..61e52d95 --- /dev/null +++ b/codec2/branches/0.7/octave/horus_tx_bits_binary.txt @@ -0,0 +1 @@ +0 0 1 0 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 1 1 0 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 1 0 1 0 0 0 0 1 0 1 0 0 1 0 1 0 1 1 0 0 1 1 0 1 1 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 1 1 1 1 1 1 1 1 0 0 1 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 0 1 0 1 1 0 1 1 1 1 0 0 1 1 0 0 1 0 1 1 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 0 1 0 0 0 1 0 0 1 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 0 1 1 0 0 0 \ No newline at end of file diff --git a/codec2/branches/0.7/octave/hp_filt.m b/codec2/branches/0.7/octave/hp_filt.m new file mode 100644 index 00000000..1087bb91 --- /dev/null +++ b/codec2/branches/0.7/octave/hp_filt.m @@ -0,0 +1,12 @@ +% hp_filt.m +% David Rowe 20 Feb 2012 + +function hp_filt(in_file, out_file) + fin = fopen(in_file,"rb"); + s = fread(fin,Inf,"short"); + b = fir1(256, 300/4000, "high"); + freqz(b); + s_hpf = filter(b,1,s); + fout = fopen(out_file,"wb"); + fwrite(fout, s_hpf, "short"); +endfunction diff --git a/codec2/branches/0.7/octave/impulse_noise.m b/codec2/branches/0.7/octave/impulse_noise.m new file mode 100644 index 00000000..dee5c5db --- /dev/null +++ b/codec2/branches/0.7/octave/impulse_noise.m @@ -0,0 +1,122 @@ +% impulse_noise +% David Rowe May 2017 +% +% Experiments with impulsive noise and HF radio + +format; +more off; +rand('seed',1) + +% DFT function ------------------------------------------------ +% note k is on 0..K-1 format, unlike Octave fft() which is 1..K + +function H = calc_H(k, K, a, d) + L = length(d); + H = 0; + for i=1:L + H += a(i)*exp(-j*2*pi*k*d(i)/K); + end +endfunction + +% ----------------------------------------- +% PWM noise simulation +% ----------------------------------------- + +function pwm_noise + + Fs = 10E6; % sample rate of simulation + Fsig = 1E6; % frequency of our wanted signal + Fpwm = 255E3; % switcher PWM frequency + T = 1; % length of simulations in seconds + Nsam = T*Fs; + Nsamplot = 200; + Apwm = 0.1; + Asig = -40; % attenuation of wanted signal in dB + + % generate an impulse train with jitter to simulate switcher noise + + pwm = zeros(1,Fs); + Tpwm = floor(Fs/Fpwm); + pulse_positions_pwm = Tpwm*(1:T*Fpwm) + round(rand(1,T*Fpwm)); + + h_pwm = zeros(1,Nsam); + h_pwm(pulse_positions_pwm) = Apwm; + h_pwm = h_pwm(1:Nsam); + + % add in wanted signal and computer amplitude spectrum + + s = 10^(Asig/20)*cos(2*pi*Fsig*(1:Nsam)/Fs); + + h = h_pwm+s; + H = fft(h); + Hdb = 20*log10(abs(H)) - 20*log10(Nsam/2); + + figure(1); clf; + subplot(211) + plot(h(1:Nsamplot)); + subplot(212) + plot(Hdb(1:Nsam/2)); + axis([0 T*2E6 -120 0]); xlabel('Frequency Hz'); ylabel('Amplityude dBV'); grid; + + printf("pwm rms: %f signal rms: %f noise rms\n", std(h_pwm), std(s)); +endfunction + +% ----------------------------------------- +% Single pulse noise simulation +% ----------------------------------------- + +function pulse_noise + + % set up short pulse in wide window, consisting of two samples next + % to each other + + K = 1024; + a(1) = a(2) = 1; d(1) = 10; d(2) = d(1)+1; + h = zeros(1,K); + h(d(1)) = a(1); + h(d(2)) = a(2); + + % mag and phase spectrum, mag spectrum changes slowly + + figure(2); clf; + Hfft = fft(h); + subplot(311) + stem(h(1:100)); + axis([1 100 -0.2 1.2]); + subplot(312) + plot(abs(Hfft(1:K/2)),'+'); + title('Magnitude'); + subplot(313) + plot(angle(Hfft(1:K/2)),'+'); + title('Phase'); + + % simple test to estimate H(k+1) from H(k) -------------------- + + % brute force calculation + + k = 300; + H = zeros(1,K); + H(k-1) = calc_H(k-1, K, a, d); + H(k) = calc_H(k, K, a, d); + H(k+1) = calc_H(k+1, K, a, d); + + % calculation of k+1 from k using approximation that {d(i)} are + % close together compared to M, i.e it's a narrow pulse (assumes we + % can estimate d using other means) + + Hk1_ = exp(-j*2*pi*d(1)/K)*H(k); + + % plot zoomed in version around k to compare + + figure(3); clf; + plot(H(k-1:k+1),'b+','markersize', 10, 'linewidth', 2); + hold on; plot(Hk1_,'g+','markersize', 10, 'linewidth', 2); hold off; + title('H(k-1) .... H(k+1)'); + printf("H(k+1) match: %f dB\n", 20*log10(abs(H(k+1) - Hk1_))); +endfunction + +% Run various simulations here --------------------------------------------- + +%pwm_noise +pulse_noise + diff --git a/codec2/branches/0.7/octave/kmeans2.m b/codec2/branches/0.7/octave/kmeans2.m new file mode 100644 index 00000000..501ef0a0 --- /dev/null +++ b/codec2/branches/0.7/octave/kmeans2.m @@ -0,0 +1,198 @@ +## Copyright (C) 2011 Soren Hauberg +## Copyright (C) 2012 Daniel Ward +## +## This program is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free Software +## Foundation; either version 3 of the License, or (at your option) any later +## version. +## +## This program is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +## details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, see . +## -*- texinfo -*- +## @deftypefn {Function File} {[@var{idx}, @var{centers}] =} kmeans2 (@var{data}, @var{k}, @var{param1}, @var{value1}, @dots{}) +## K-means clustering. +## +## @seealso{linkage} +## @end deftypefn + +function [classes, centers, sumd, D] = kmeans2 (data, k, varargin) + + [reg, prop] = parseparams (varargin); + + ## defaults for options + + emptyaction = "error"; + start = "sample"; + + # used for getting the number of samples + + nRows = rows (data); + + ## used to hold the distances from each sample to each class + + D = zeros (nRows, k); + + # used for convergence of the centroids + + err = 1; + + # initial sum of distances + + sumd = Inf; + + # default search function, can be over-ridden by user supplied function + + search_func = @vq_search_mse; + + ## Input checking, validate the matrix and k + + if (!isnumeric (data) || !ismatrix (data) || !isreal (data)) + error ("kmeans: first input argument must be a DxN real data matrix"); + elseif (!isscalar (k)) + error ("kmeans: second input argument must be a scalar"); + endif + + if (length (varargin) > 0) + + ## check for the ‘emptyaction’ property + + found = find (strcmpi (prop, "emptyaction") == 1); + if found + switch (lower (prop{found+1})) + case "singleton" + emptyaction = "singleton"; + otherwise + error ("kmeans: unsupported empty cluster action parameter"); + endswitch + end + + ## check for the ‘search_func’ property, user defined vq_search function + + found = find (strcmpi (prop, "search_func") == 1); + if found + search_func = prop{found+1}; + end + + ## check for the ‘start’ property + + found = find (strcmpi (prop, "start") == 1); + if found + switch (lower (prop{found+1})) + case "sample" + idx = randperm (nRows) (1:k); + centers = data (idx, :); + case "first" + centers = data (1:k, :); + otherwise + error ("kmeans: unsupported initial clustering parameter"); + endswitch + end + end + + ## Run the algorithm + + while err > .001 + classes = feval(search_func, centers, data); + + ## Calculate new centroids + + for i = 1:k + + ## Get binary vector indicating membership in cluster i + + membership = (classes == i); + + ## Check for empty clusters + + if (sum (membership) == 0) + switch emptyaction + + ## if ‘singleton’, then find the point that is the + ## farthest and add it to the empty cluster + + case 'singleton' + idx=maxCostSampleIndex (data, centers(i,:)); + classes(idx) = i; + membership(idx)=1; + ## if ‘error’ then throw the error + otherwise + error ("kmeans: empty cluster created"); + endswitch + endif ## end check for empty clusters + + ## update the centroids + + members = data(membership, :); + centers(i, :) = sum(members,1)/size(members,1); + endfor + + ## calculate the difference in the sum of distances + + err = sumd - objCost (data, classes, centers); + + ## update the current sum of distances + + sumd = objCost (data, classes, centers); + + endwhile +endfunction + + +function idx = vq_search_mse(vq, data) + [nVec nCols] = size(vq); + nRows = length(data); + + error = zeros(1,nVec); + idx = zeros(1, nRows); + + for f=1:nRows + target = data(f,:); + for i=1:nVec + diff = target - vq(i,:); + error(i) = diff * diff'; + end + [mn min_ind] = min(error); + idx(f) = min_ind; + end +endfunction + + +## calculate the sum of distances + +function obj = objCost (data, classes, centers) + obj = 0; + for i=1:rows (data) + obj = obj + sumsq (data(i,:) - centers(classes(i),:)); + endfor +endfunction + +function idx = maxCostSampleIndex (data, centers) + cost = 0; + for idx = 1:rows (data) + if cost < sumsq (data(idx,:) - centers) + cost = sumsq (data(idx,:) - centers); + endif + endfor +endfunction + +%!demo +%! ## Generate a two-cluster problem +%! C1 = randn (100, 2) + 1; +%! C2 = randn (100, 2) – 1; +%! data = [C1; C2]; +%! +%! ## Perform clustering +%! [idx, centers] = kmeans (data, 2); +%! +%! ## Plot the result +%! figure +%! plot (data (idx==1, 1), data (idx==1, 2), ‘ro’); +%! hold on +%! plot (data (idx==2, 1), data (idx==2, 2), ‘bs’); +%! plot (centers (:, 1), centers (:, 2), ‘kv’, ‘markersize’, 10); +%! hold off diff --git a/codec2/branches/0.7/octave/kmeans_tests.m b/codec2/branches/0.7/octave/kmeans_tests.m new file mode 100644 index 00000000..9b4d8837 --- /dev/null +++ b/codec2/branches/0.7/octave/kmeans_tests.m @@ -0,0 +1,765 @@ +% kmeans_tests.m +% +% David Rowe June 2017 +% +% +% Trying a few variations on the kmeans algorithm for quantisation of +% spectral envelope + +1; + +%---------------------------------------------------------------------- +% +% User defined search functions +% +%---------------------------------------------------------------------- + +%---------------------------------------------------------------------- +% standard mean squared error search + +function [idx contrib errors test_ g mg sl] = vq_search_mse(vq, data) + [nVec nCols] = size(vq); + nRows = rows(data); + + error = zeros(1,nVec); + errors = zeros(1, nRows); + idx = zeros(1, nRows); + contrib = zeros(nRows, nCols); + test_ = zeros(nVec, nCols); + + for f=1:nRows + target = data(f,:); + for i=1:nVec + diff = target - vq(i,:); + error(i) = diff * diff'; + end + [mn min_ind] = min(error); + errors(f) = mn; idx(f) = min_ind; contrib(f,:) = vq(min_ind,:); + test_(f,:) = vq(min_ind,:); + end + + g = 0; mg = 1; sl = 0; % dummys for this function +endfunction + + +%---------------------------------------------------------------------- +% abs() search with a linear gain term + +function [idx contrib errors test_ g mg sl] = vq_search_gain(vq, data) + + [nVec nCols] = size(vq); + nRows = rows(data); + + error = zeros(1,nVec); + g = zeros(nRows, nVec); + diff = zeros(nVec, nCols); + errors = zeros(1, nRows); + idx = zeros(1, nRows); + contrib = zeros(nRows, nCols); + test_ = zeros(nVec, nCols); + + for f=1:nRows + target = data(f,:); + for i=1:nVec + % work out gain for best match + + g(f, i) = (sum(target) - sum(vq(i,:)))/nCols; + diff(i,:) = target - vq(i,:) - g(f, i); + + % abs in dB is MSE in linear + + error(i) = mean(abs(diff(i,:))); + + %printf("f: %d i: %d g: %f error: %f\n", f, i, g(f, i), error(i)); + end + [mn min_ind] = min(error); + + idx(f) = min_ind; + + errors(f) = mn; + contrib(f,:) = test_(f,:) = vq(min_ind,:) + g(f,min_ind); + end + mg = 1; sl = 0; +endfunction + + +%---------------------------------------------------------------------- +% abs() search with a linear plus ampl scaling term + +function [idx contrib errors test_ g mg sl] = vq_search_mag(vq, data) + [nVec nCols] = size(vq); + nRows = rows(data); + + g = mg = zeros(nRows, nVec); + diff = zeros(nVec, nCols); + errors = zeros(1, nRows); + idx = error = zeros(1, nVec); + contrib = zeros(nRows, nCols); + test_ = zeros(nVec, nCols); + + weights = ones(1,nCols); + %weights(1) = 0; + + for f=1:nRows + target = data(f,:); + %target = 2*vq(1,:)+1; + + for i=1:nVec + % work out gain and amp scaling for best match + + A = [sum(vq(i,:)) nCols; vq(i,:)*vq(i,:)' sum(vq(i,:))]; + c = [sum(target) target*vq(i,:)']'; + b = inv(A)*c; + + g(f,i) = b(2); mg(f,i) = b(1); + diff(i,:) = target - (mg(f,i)*vq(i,:) + g(f,i)); + diff(i,:) .* weights; + + % abs in dB is MSE in linear + + error(i) = mean(abs(diff(i,:))); + + %printf("f: %d i: %d mg: %f g: %f error: %f\n", f, i, mg(f,i), g(f,i), error(i)); + end + + [mn min_ind] = min(error); + errors(f) = mn; + idx(f) = min_ind; + + contrib(f,:) = test_(f,:) = mg(f,min_ind) * vq(min_ind,:) + g(f,min_ind); + end + sl = 0; +endfunction + + +%---------------------------------------------------------------------- +% abs() search with a linear, ampl scaling, and slope term + +function [idx contrib errors test_ g mg sl] = vq_search_slope(vq, data) + [nVec nCols] = size(vq); + nRows = rows(data); + + g = mg = sl = zeros(nRows, nVec); + diff = zeros(nVec, nCols); + errors = zeros(1, nRows); + idx = error = zeros(1, nVec); + contrib = zeros(nRows, nCols); + test_ = zeros(nVec, nCols); + + weights = ones(1,nCols); + + for f=1:nRows + target = data(f,:); + %target = 2*vq(1,:)+1; + + for i=1:nVec + % work out gain, amp and slope for best match, 3 unknowns, 3 equations + + A = [sum(vq(i,:)) nCols sum(1:nCols); ... + vq(i,:)*vq(i,:)' sum(vq(i,:)) (1:nCols)*vq(i,:)'; ... + (1:nCols)*vq(i,:)' sum(1:nCols) (1:nCols)*(1:nCols)']; + c = [sum(target) target*vq(i,:)' target*(1:nCols)']'; + b = inv(A)*c; + + mg(f,i) = b(1); g(f,i) = b(2); sl(f,i) = b(3); + diff(i,:) = target - (mg(f,i)*vq(i,:) + g(f,i) + sl(f,i)*(1:nCols)); + diff(i,:) .* weights; + + % abs in dB is MSE in linear + + error(i) = mean(abs(diff(i,:))); + + %printf("f: %d i: %d mg: %f g: %f sl: %f error: %f\n", f, i, mg(f,i), g(f,i), sl(f,i), error(i)); + end + + [mn min_ind] = min(error); + errors(f) = mn; + idx(f) = min_ind; + + contrib(f,:) = test_(f,:) = mg(f,min_ind)*vq(min_ind,:) + g(f,min_ind) + sl(f,min_ind)*(1:nCols); + end + +endfunction + + +%---------------------------------------------------------------------- +% +% Functions to support simulation of different VQ training and testing +% +%---------------------------------------------------------------------- + +% evaluate database test using vq, with selectable search function. Can be operated in +% GUI mode to analyse in fine detail or batch mode to evaluate lots of data. + +function sd_per_frame = run_test(vq, test, nVec, search_func, gui_en = 0) + + % Test VQ using test data ----------------------- + + % Each test must output: + % errors: - error for best vector + % idx...: - index of best vector + % test_.: - best approximation of target test database + + [nRows nCols] = size(test); + + [idx contrib errors test_ g mg sl] = feval(search_func, vq, test); + + % sd over time + + sd_per_frame = zeros(nRows,1); + for i=1:nRows + sd_per_frame(i) = mean(abs(test(i,:) - test_(i,:))); + end + + printf("average sd: %3.2f\n", mean(sd_per_frame)); + %printf("%18s nVec: %d SD: %3.2f dB\n", search_func, nVec, mean(sd_per_frame)); + + % Optional GUI with U to anlayse VQ perf --------------------------------------------------- + + if gui_en + gui_mode = "sort"; % "sort" or "fbf" + sort_order = "worst"; % "worst" or "best" + f = 1; + + % plots sd over time and histogram + + figure(1); clf; subplot(211); plot(sd_per_frame); title('SD'); + subplot(212); [yy xx] = hist(sd_per_frame); plot(xx,yy,'+-'); + end + + while gui_en + + % display m frames, printing some stats, plotting vector to give visual idea of match + + figure(2); clf; + + % try this in 'ascend' or 'descend' mode to best or worst frames + + if strcmp(gui_mode, "sort") + if strcmp(sort_order, "best") + [errors_dec frame_dec] = sort(errors, "ascend"); + end + if strcmp(sort_order, "worst") + [errors_dec frame_dec] = sort(errors, "descend"); + end + m = 4; + else + m = 1; + errors_dec = errors(f); frame_dec(1) = f; + end + + for i=1:m + + % build up VQ legend + + af = frame_dec(i); aind = idx(af); + + ag = 0; amg = 1; asl = 0; + if strcmp(search_func, "vq_search_gain") + ag = g(af,aind); + l3 = sprintf("g: %3.2f", ag); + end + if strcmp(search_func, "vq_search_mag") + ag = g(af,aind); + amg = mg(af,aind); + l3 = sprintf("g: %3.2f mg: %3.2f", ag, amg); + end + if strcmp(search_func, "vq_search_slope") + ag = g(af,aind); + amg = mg(af,aind); + asl = sl(af,aind); + l3 = sprintf("g: %3.2f mg: %3.2f sl: %3.2f", ag, amg, asl); + end + + % plot target + + subplot(sqrt(m), sqrt(m),i); + l1 = sprintf("b-;fr %d sd: %3.2f;", af, errors_dec(m)); + plot(test(af,:), l1); + + % plot vq vector and modified version + + hold on; + l2 = sprintf("g-+;ind %d;", aind); + plot(vq(aind, :), l2); + l3 = sprintf("g-o;%s;",l3); + plot(amg*vq(aind, :) + ag + asl*(1:nCols), l3); + hold off; + axis([1 nCols -10 40]); + end + + % interactive menu ------------------------------------------ + + if strcmp(gui_mode, "sort") + printf("\rmenu: m-mode[%s] o-order[%s] q-quit", gui_mode, sort_order); + end + if strcmp(gui_mode, "fbf") + printf("\rmenu: m-mode[%s] frame: %d n-next b-back q-quit", gui_mode, f); + end + fflush(stdout); + k = kbhit(); + + if k == 'm' + if strcmp(gui_mode, "sort") + gui_mode = "fbf"; f = frame_dec(1); + else + gui_mode = "sort"; + end; + end + if k == 'o' + if strcmp(sort_order, "worst") + sort_order = "best"; + else + sort_order = "worst"; + end; + end + if k == 'n', f = f + 1; endif; + if k == 'b', f = f - 1; endif; + if k == 'q', gui_en = 0; printf("\n"); endif; + end + +endfunction + + +function search_func = get_search_func(short_name) + if strcmp(short_name, "mse") + search_func = 'vq_search_mse'; + end + if strcmp(short_name, "gain") + search_func = 'vq_search_gain'; + end + if strcmp(short_name, "mag") + search_func = 'vq_search_mag'; + end + if strcmp(short_name, "slope") + search_func = 'vq_search_slope'; + end +end + + +%---------------------------------------------------------------------- +% Train up a VQ and run one or mode tests + +function [sd des] = train_vq_and_run_tests(sim_in) + Nvec = sim_in.Nvec; + + train_func = get_search_func(sim_in.train_func_short); + printf(" Nvec %d kmeans start\n", Nvec); + [idx vq] = feval(sim_in.kmeans, + sim_in.trainvec, Nvec, + "start", "sample", + "emptyaction", "singleton", + "search_func", train_func); + printf(" Nvec %d kmeans end\n", Nvec); + + sd = []; des = []; tests = sim_in.tests; + for t=1:length(cellstr(tests)) + test_func_short = char(cellstr(tests)(t)); + test_func = get_search_func(test_func_short); + asd = run_test(vq, sim_in.testvec, Nvec, test_func); + sd = [sd asd]; + ades.Nvec = Nvec; + ades.train_func_short = sim_in.train_func_short; + ades.test_func_short = test_func_short; + ades_str = sprintf("Nvec: %3d train: %-5s test: %-5s", + ades.Nvec, ades.train_func_short, ades.test_func_short); + des = [des ades]; + printf(" %s SD: %3.2f\n", ades_str, mean(asd)); + end + +endfunction + +% Search for test that matchs train/test and any Nvec and constructs points for error bar plot + +function [y x leg] = search_tests(sd, desc, train, test) + nTests = length(desc) + x = []; y = []; leg = []; + for i=1:nTests + if strcmp(desc(i).train_func_short, train) && strcmp(desc(i).test_func_short, test) + printf("i: %2d Nvec: %3d train: %5s test: %5s\n", i, desc(i).Nvec, desc(i).train_func_short, desc(i).test_func_short); + x = [x; log2(desc(i).Nvec)]; + y = [y; mean(sd(:,i)) std(sd(:,i))]; + end + end +endfunction + + +function plot_sd_results(fg, title_str, sd, desc, train_list, test_list) + figure(fg); clf; + + nlines = 0; inc = -0.1; + for i=1:length(cellstr(train_list)) + train_func_short = char(cellstr(train_list)(i)); + for j=1:length(cellstr(test_list)) + test_func_short = char(cellstr(test_list)(j)); + [y x] = search_tests(sd, desc, train_func_short, test_func_short); + leg = sprintf("o-%d;train: %5s test: %5s;", nlines, train_func_short, test_func_short); + if nlines, hold on; end; + x += inc; inc += 0.1; % separate x coords a bit to make errors bars legible + errorbar(x, y(:,1), y(:,2), leg); + nlines++; + end + if nlines>1, hold off; end; + end + + xlabel('VQ size (bits)') + ylabel('mean SD (dB)'); + title(title_str); +endfunction + + +% Search for test that matches all fields for histogram plots + +function testNum = search_tests_Nvec(sd, desc, train, test, Nvec) + nTests = length(desc); + testNum = 0; + for i=1:nTests + if strcmp(desc(i).train_func_short, train) && strcmp(desc(i).test_func_short, test) && desc(i).Nvec == Nvec + printf("i: %2d Nvec: %3d train: %5s test: %5s\n", i, desc(i).Nvec, desc(i).train_func_short, desc(i).test_func_short); + testNum = i; + end + end +endfunction + +%---------------------------------------------------------------------- +% +% Plot histograms of SDs for comparison. Each col of sd_per_frame +% has the results of one test, number of cols % is number of tests. leg +% is a col vector with one legend string for each test. + +function compare_hist(fg, atitle, sd, desc) + figure(fg); clf; + [nRows nCols] = size(sd); + for c=1:nCols + [yy, xx] = hist(sd(:, c)); + if c == 2, hold on; end; + leg = sprintf("o-%d;train: %5s test: %5s;", c-1, desc(c).train_func_short, desc(c).test_func_short); + plot(xx, yy, leg); + end + if nCols > 1, hold off; end; + title(atitle) +end + +%---------------------------------------------------------------------- +% Run a bunch of long tests in parallel and plot results +% + +% This test tries a bunch of training and test search combinations on +% the first 1kHz to see if there is any advantage in using the higher +% order search techniques in the VQ training. So far it appears +% not.... However the higher order search routines do give great +% results compared to a basic MSE (or oder) search. + +function [sd desc] = long_tests_1_10(quick_check=0) + num_cores = 4; + K = 10; + load surf_train_120_hpf150; load surf_all_hpf150; + + if quick_check + NtrainVec = 1000; + NtestVec = 100; + else + NtrainVec = length(surf_train_120_hpf150); + NtestVec = length(surf_all_hpf150); + end + + trainvec = surf_train_120_hpf150(1:NtrainVec,1:K); + testvec = surf_all_hpf150(1:NtestVec,1:K); + + % build up a big array of tests to run ------------------------ + + sim_in.trainvec = trainvec; sim_in.testvec = testvec; + sim_in.kmeans = "kmeans2"; % slow but supports different search functions + sim_in.Nvec = 64; + sim_in.train_func_short = "mse"; + sim_in.tests = ["mse"; "gain"; "mag"; "slope"]; + + % Test1: mse training, 64, 128, 256 + + sim_in_vec(1:3) = sim_in; + sim_in_vec(2).Nvec = 128; sim_in_vec(3).Nvec = 256; + + test_list = sim_in_vec; + + % Test2: gain training, 64, 128, 256 + + for i=1:3, sim_in_vec(i).train_func_short = "gain"; end; + test_list = [test_list sim_in_vec]; + + % Test3: mag training, 64, 128, 256 + + for i=1:3, sim_in_vec(i).train_func_short = "mag"; end; + test_list = [test_list sim_in_vec]; + + % Test4: slope training, 64, 128, 256 + + for i=1:3, sim_in_vec(i).train_func_short = "slope"; end; + test_list = [test_list sim_in_vec]; + + % run test list in parallel + + [sd desc] = pararrayfun(num_cores, @train_vq_and_run_tests, test_list); + %train_vq_and_run_tests(test_list(1)); + + % Plot results ----------------------------------------------- + + fg = 1; + plot_sd_results(fg++, "MSE Training", sd, desc, "mse", ["mse"; "gain"; "mag"; "slope"]); + plot_sd_results(fg++, "Gain Training", sd, desc, "gain", ["mse"; "gain"; "mag"; "slope"]); + plot_sd_results(fg++, "Mag Training", sd, desc, "mag", ["mse"; "gain"; "mag"; "slope"]); + plot_sd_results(fg++, "Slope Training", sd, desc, "slope", ["mse"; "gain"; "mag"; "slope"]); + plot_sd_results(fg++, "Slope Searching", sd, desc, ["mse"; "gain"; "mag"; "slope"], "slope"); + + % histogram of results from Nvec=64, all training methods, slope search + + testnum = search_tests_Nvec(sd, desc, "mse", "slope", 64); + hist_sd = sd(:,testnum); hist_desc = desc(testnum); + testnum = search_tests_Nvec(sd, desc, "gain", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + testnum = search_tests_Nvec(sd, desc, "mag", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + testnum = search_tests_Nvec(sd, desc, "slope", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + compare_hist(fg, "Histogram of SDs Nvec=64", hist_sd, hist_desc); + +endfunction + + +%---------------------------------------------------------------------- +% This test tries some test combinations on the 1000 to 3000 Hz range. +% +% Based on our results with long_test_1_10() we just use MSE training + +function [sd desc] = long_tests_11_40(quick_check=0) + num_cores = 4; + K = 20; st = 11; en = 40; + load surf_train_120_hpf150; load surf_all_hpf150; + + if quick_check + NtrainVec = 1000; + NtestVec = 100; + else + NtrainVec = length(surf_train_120_hpf150); + NtestVec = length(surf_all_hpf150); + end + + trainvec = surf_train_120_hpf150(1:NtrainVec,st:en); + testvec = surf_all_hpf150(1:NtestVec,st:en); + + % build up an array of tests to run ------------------------ + + sim_in.kmeans = "kmeans"; + sim_in.trainvec = trainvec; sim_in.testvec = testvec; + sim_in.Nvec = 64; + sim_in.train_func_short = "mse"; + sim_in.tests = ["slope"]; + + % Test1: mse training, 64, 128, 256, 512 + + sim_in_vec(1:4) = sim_in; + sim_in_vec(2).Nvec = 128; sim_in_vec(3).Nvec = 256; sim_in_vec(4).Nvec = 512; + + test_list = sim_in_vec; + + % run test list in parallel + + [sd desc] = pararrayfun(num_cores, @train_vq_and_run_tests, test_list); + %[sd desc] = train_vq_and_run_tests(sim_in_vec(4)); + + % Plot results ----------------------------------------------- + + fg = 2; + plot_sd_results(fg++, "MSE Training 10..30", sd, desc, "mse", "slope"); + +#{ + % histogram of results from Nvec=64, all training methods, slope search + + testnum = search_tests_Nvec(sd, desc, "mse", "slope", 64); + hist_sd = sd(:,testnum); hist_desc = desc(testnum); + testnum = search_tests_Nvec(sd, desc, "gain", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + testnum = search_tests_Nvec(sd, desc, "mag", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + testnum = search_tests_Nvec(sd, desc, "slope", "slope", 64); + hist_sd = [hist_sd sd(:,testnum)]; hist_desc = [hist_desc desc(testnum)]; + compare_hist(fg, "Histogram of SDs Nvec=64", hist_sd, hist_desc); +#} +endfunction + + +function vq = detailed_test(Nvec=64, st=1, en=10, quick_check=1, test_func = "vq_search_slope") + K = en-st+1; + load surf_train_120_hpf150; + load surf_all_hpf150; + if quick_check + NtrainVec = 1000; + NtestVec = 100; + else + NtrainVec = length(surf_train_120_hpf150); + NtestVec = length(surf_all_hpf150); + NtestVec = 100; + end + + trainvec = surf_train_120_hpf150(1:NtrainVec,st:en); + testvec = surf_all_hpf150(1:NtestVec,st:en); + + [idx vq] = kmeans(trainvec, Nvec, + "start", "sample", + "emptyaction", "singleton"); + + run_test(vq, testvec, Nvec, test_func, gui_en=1); +endfunction + + +% ------------------------------------------------------------------ +% +% Following test_* functions have some contrived examples to test VQ +% training with each training method. However the longtest_1_10 +% results suggest these training methds don't provide any improvement +% over standard MSE kmeans. + +function test_training_mse + K = 3; NtrainVec = 10; Nvec = 2; + + trainvec = ones(NtrainVec,K); + trainvec(2:2:NtrainVec,:) = -1; + + [idx vq] = kmeans2(trainvec, Nvec, + "start", "first", + "emptyaction", "singleton", + "search_func", "vq_search_mse"); + + ok = find(vq == [1 1 1]) && (find(vq == [-1 -1 -1])); + printf("ok: %d\n", ok); +endfunction + + +function test_training_gain + K = 3; NtrainVec = 10; Nvec = 2; + + % Vectors that are the same, but offset from each other via a linear + % term. Training algorithm should map these all to the "same" + % vector. + + trainvec = ones(NtrainVec,K); + for v=2:NtrainVec/2 + trainvec(v,:) += v*ones(1,1:K); + end + + % Second set of "identical" vectors except for gain offset + + for v=NtrainVec/2+1:NtrainVec + trainvec(v,:) = [1 0 -1] + (v-NtrainVec/2-1)*ones(1,1:K); + end + + [idx vq] = kmeans2(trainvec, Nvec, + "start", "sample", + "emptyaction", "singleton", + "search_func", "vq_search_gain"); + + % check we get a vq table of two vectors that are linear offset [1 1 1] and [1 0 -1] + + tol = 0.001; ok = 0; + for i=1:Nvec + diff = vq(i,:) - [1 1 1]; + if std(diff) < tol, ok++; end; + diff = vq(i,:) - [1 0 -1]; + if std(diff) < tol, ok++; end; + end + if ok == 2, printf("gain: OK\n"); end; +endfunction + + +function test_training_mag + K = 3; NtrainVec = 10; Nvec = 2; + + % Given a vector x, create a set of training data y = m*x + c, with x + % modified by a magnitude and linear term. Each vector has a + % different mag and linear term. + + trainvec = zeros(NtrainVec,K); + for v=1:2:NtrainVec + trainvec(v,:) = v*[1 2 3] + 2*v; + end + + % another set of "identical" vectors, mapped by different magnitude and linear terms, + % alternated with the frist set so we can use the "start:first" to populate the VQ + + for v=2:2:NtrainVec + trainvec(v,:) = cos(v)*[2 -1 2] -2*v; + end + + trainvec + + [idx vq] = kmeans2(trainvec, Nvec, + "start", "first", + "search_func", "vq_search_mag"); + + vq + + % todo: how to auto test? Need to solve same euqations? +#} + tol = 0.001; ok = 0; + for i=1:Nvec + diff = vq(i,:) - [1 1 1]; + if std(diff) < tol, ok++; end; + diff = vq(i,:) - [1 0 -1]; + if std(diff) < tol, ok++; end; + end + if ok == 2, printf("gain: OK\n"); end; +#} +endfunction + + +function test_training_slope + K = 40; NtrainVec = 5; Nvec = 1; + + % Given a vector x, create a set of training data y = m*x + c + sl, where: + % x is a vector + % c is a constant offset + % m is a magnitude multiplier on all elements of x + % sl is a linear slope vector + + load surf_all; + prototype = surf_all(73,:); + trainvec = zeros(NtrainVec,K); + for v=1:NtrainVec + trainvec(v,:) = 2*prototype + 1 + v*(1:K); + end + figure(1); clf; plot(trainvec'); + + [idx vq] = kmeans2(trainvec, Nvec, + "start", "first", + "search_func", "vq_search_slope"); + + + [idx contrib errors test_ g mg sl] = vq_search_slope(prototype, trainvec) + + % todo: how to auto test? Need to solve same euqations? +#{ + tol = 0.001; ok = 0; + for i=1:Nvec + diff = vq(i,:) - [1 1 1]; + if std(diff) < tol, ok++; end; + diff = vq(i,:) - [1 0 -1]; + if std(diff) < tol, ok++; end; + end + if ok == 2, printf("gain: OK\n"); end; +#} +endfunction + +% --------------------------------------------------------- + +format; more off; +rand('seed',1); % kmeans using rand for initial population, + % we want same results on every run + +% choose one of these to run + +detailed_test(64, 1, 20, quick_check=1); +%[sd desc] = long_tests_1_10(quick_check=1); +%[sd desc] = long_tests_11_40(quick_check=0); +%test_training_slope + + + diff --git a/codec2/branches/0.7/octave/ldpc.m b/codec2/branches/0.7/octave/ldpc.m new file mode 100644 index 00000000..3cbf7fe6 --- /dev/null +++ b/codec2/branches/0.7/octave/ldpc.m @@ -0,0 +1,143 @@ +% ldpc.m +% +% David Rowe 2013 +% Octave functions to help us use the CML LDPC code. +% +% Installing CML library +% ---------------------- +% +% $ sudo apt-get install liboctave-dev +% $ wget http://www.iterativesolutions.com/user/image/cml.1.10.zip +% $ unzip cml.1.10.zip +% $ patch -p0 < ~/codec2-dev/octave/cml.patch +% $ cd cml/source +% $ octave +% octave:> make +% (you'll see a few warnings but hopefully no errors) + +1; + +% NOTE: You will need to set the CML path in the call to init_cml() below +% for you CML install. See lpdc.m for instructions on how to install +% CML library + +function init_cml(path_to_cml) + currentdir = pwd; + + if exist(path_to_cml, 'dir') == 7 + cd(path_to_cml) + CmlStartup + cd(currentdir); + else + printf("\n---------------------------------------------------\n"); + printf("Can't start CML in path: %s\n", path_to_cml); + printf("See CML path instructions at top of this script\n"); + printf("-----------------------------------------------------\n\n"); + assert(0); + end +end + +% init using built in WiMax code + +function code_param = ldpc_init_wimax(rate, framesize, modulation, mod_order, mapping) + [code_param.H_rows, code_param.H_cols, code_param.P_matrix] = InitializeWiMaxLDPC( rate, framesize, 0 ); + code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); + code_param.S_matrix = CreateConstellation( modulation, mod_order, mapping ); + code_param.bits_per_symbol = log2(mod_order); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/code_param.bits_per_symbol; +endfunction + + +% init using user supplied code + +function [code_param framesize rate] = ldpc_init_user(HRA, modulation, mod_order, mapping) + [Nr Nc] = size(HRA); + rate = (Nc-Nr)/Nc; + framesize = Nc; + [H_rows, H_cols] = Mat2Hrows(HRA); + code_param.H_rows = H_rows; + code_param.H_cols = H_cols; + code_param.P_matrix = []; + code_param.data_bits_per_frame = length(code_param.H_cols) - length(code_param.P_matrix); + code_param.S_matrix = CreateConstellation( modulation, mod_order, mapping ); + code_param.bits_per_symbol = log2(mod_order); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/code_param.bits_per_symbol; +endfunction + + +function [codeword s] = ldpc_enc(data, code_param) + codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix ); + s = Modulate( codeword, code_param.S_matrix ); +endfunction + + +function detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading) + if nargin == 6 + fading = ones(1, length(r)); + end + + symbol_likelihood = Demod2D( r, code_param.S_matrix, EsNo, fading); + + % initialize the extrinsic decoder input + + input_somap_c = zeros(1, code_param.code_bits_per_frame ); + bit_likelihood = Somap( symbol_likelihood, demod_type, input_somap_c ); + + input_decoder_c = bit_likelihood(1:code_param.code_bits_per_frame); + + x_hat= MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ... + max_iterations, decoder_type, 1, 1); + detected_data = x_hat(max_iterations,:); +endfunction + + +% Packs a binary array into an array of 8 bit bytes, MSB first + +function packed = packmsb(unpacked) + packed = zeros(1,floor(length(unpacked)+7)/8); + bit = 7; byte = 1; + for i=1:length(unpacked) + packed(byte) = bitor(packed(byte), bitshift(unpacked(i),bit)); + bit--; + if (bit < 0) + bit = 7; + byte++; + end + end +endfunction + + +% unpacks an array of 8 bit bytes into a binary array of unpacked bits, MSB first + +function unpacked = unpackmsb(packed) + bit = 7; byte = 1; + for i=1:length(packed)*8 + unpacked(i) = bitand(bitshift(packed(byte), -bit), 1); + bit--; + if (bit < 0) + bit = 7; + byte++; + end + end +endfunction + + +% symbol interleaver that acts on bits 2 at a time + +function y = interleave_bits(interleaver, x) + y = zeros(1,length(x)); + for i = 1:length(interleaver) + dst = interleaver(i); + y(2*(dst-1)+1:2*dst) = x(2*(i-1)+1:2*(i)); + end +endfunction + +% symbol de-interleaver + +function x = deinterleave_symbols(interleaver, y) + for i = 1:length(interleaver) + x(i) = y(interleaver(i)); + end +endfunction diff --git a/codec2/branches/0.7/octave/ldpc_fsk_lib.m b/codec2/branches/0.7/octave/ldpc_fsk_lib.m new file mode 100644 index 00000000..661758da --- /dev/null +++ b/codec2/branches/0.7/octave/ldpc_fsk_lib.m @@ -0,0 +1,269 @@ +% lpdc_fsk_lib.m +% April 2015 +% +% Library version of ldpc4.m written by vk5dsp. Application is high bit rate +% balloon telemtry +% +% LDPC demo +% Call the CML routines and simulate one set of SNRs. +% This fucntion is an updated version of ldpc3() which uses less +% of the CML functions +% +% sim_in the input parameter structure +% sim_out contains BERs and other stats for each value of SNR +% resfile is the result file +% + +1; + +function sim_out = ldpc5(sim_in, resfile, testmode, genie_Es, logging=0); + + if nargin<4, testmode = 0; end + estEsN0 = 0; + + HRA = sim_in.HRA; + framesize = sim_in.framesize; + rate = sim_in.rate; + mod_order = sim_in.mod_order; + + Lim_Ferrs = sim_in.Lim_Ferrs; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + code_param = ldpc_init(HRA, mod_order); + bps = code_param.bits_per_symbol; + + + if (logging) + fod = fopen('decode.log', 'w'); + fwrite(fod, 'Es estEs Its secs \n'); + end + + + for ne = 1:length(Esvec) + Es = Esvec(ne); + EsNo = 10^(Es/10); + + + Terrs = 0; Tbits =0; Ferrs =0; + for nn = 1: Ntrials + + data = round( rand( 1, code_param.data_bits_per_frame ) ); + codeword = ldpc_encode(code_param, data); + + code_param.code_bits_per_frame = length( codeword ); + Nsymb = code_param.code_bits_per_frame/bps; + + if testmode==1 + f1 = fopen("dat_in2064.txt", "w"); + for k=1:length(data); fprintf(f1, "%u\n", data(k)); end + fclose(f1); + system("./ra_enc"); + + load("dat_op2064.txt"); + pbits = codeword(length(data)+1:end); % print these to compare with C code + dat_op2064(1:16)', pbits(1:16) + differences_in_parity = sum(abs(pbits - dat_op2064')) + pause; + end + + + % modulate + % s = Modulate( codeword, code_param.S_matrix ); + s= 1 - 2 * codeword; + code_param.symbols_per_frame = length( s ); + + variance = 1/(2*EsNo); + noise = sqrt(variance)* randn(1,code_param.symbols_per_frame); + % + j*randn(1,code_param.symbols_per_frame) ); + r = s + noise; + Nr = length(r); + + [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type); + + error_positions = xor( detected_data(1:code_param.data_bits_per_frame), data ); + Nerrs = sum( error_positions); + + t = clock; t = fix(t(5)*60+t(6)); + if (logging) + fprintf(fod, ' %3d %4d\n', Niters, t); + end + + if Nerrs>0, fprintf(1,'x'), else fprintf(1,'.'), end + if (rem(nn, 50)==0), fprintf(1,'\n'), end + + if Nerrs>0, Ferrs = Ferrs +1; end + Terrs = Terrs + Nerrs; + Tbits = Tbits + code_param.data_bits_per_frame; + + if Ferrs > Lim_Ferrs, disp(['exit loop with #cw errors = ' ... + num2str(Ferrs)]); break, end + end + + TERvec(ne) = Terrs; + FERvec(ne) = Ferrs; + BERvec(ne) = Terrs/ Tbits; + Ebvec = Esvec - 10*log10(code_param.bits_per_symbol * rate); + + cparams= [code_param.data_bits_per_frame code_param.symbols_per_frame ... + code_param.code_bits_per_frame]; + + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.FERvec = FERvec; + sim_out.TERvec = TERvec; + sim_out.cpumins = cputime/60; + + if nargin > 2 + save(resfile, 'sim_in', 'sim_out', 'cparams'); + disp(['Saved results to ' resfile ' at Es =' num2str(Es) 'dB']); + end + end +end + + +function code_param = ldpc_init(HRA, mod_order) + code_param.bits_per_symbol = log2(mod_order); + [H_rows, H_cols] = Mat2Hrows(HRA); + code_param.H_rows = H_rows; + code_param.H_cols = H_cols; + code_param.P_matrix = []; + code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); + code_param.symbols_per_frame = length(HRA); +end + + +function codeword = ldpc_encode(code_param, data) + codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix ); +endfunction + + +% Takes soft decision symbols (e.g. output of 2fsk demod) and converts +% them to LLRs. Note we calculate mean and var manually instead of +% using internal functions. This was required to get a bit exact +% results against the C code. + +function llr = sd_to_llr(sd) + sd = sd / mean(abs(sd)); + x = sd - sign(sd); + sumsq = sum(x.^2); + summ = sum(x); + mn = summ/length(sd); + estvar = sumsq/length(sd) - mn*mn; + estEsN0 = 1/(2* estvar + 1E-3); + llr = 4 * estEsN0 * sd; +endfunction + + +% LDPC decoder - note it estimates EsNo from received symbols + +function [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type) + % in the binary case the LLRs are just a scaled version of the rx samples .. + + #{ + r = r / mean(abs(r)); % scale for signal unity signal + estvar = var(r-sign(r)); + estEsN0 = 1/(2* estvar + 1E-3); + input_decoder_c = 4 * estEsN0 * r; + #} + llr = sd_to_llr(r); + + [x_hat, PCcnt] = MpDecode(llr, code_param.H_rows, code_param.H_cols, ... + max_iterations, decoder_type, 1, 1); + Niters = sum(PCcnt!=0); + detected_data = x_hat(Niters,:); + + if isfield(code_param, "c_include_file") + ldpc_gen_h_file(code_param, max_iterations, decoder_type, llr, x_hat, detected_data); + end +end + + +% One application of FSK LDPC work is SSTV. This function generates a +% simulated frame for testing + +function frame_rs232 = gen_sstv_frame + load('H2064_516_sparse.mat'); + HRA = full(HRA); + mod_order = 2; + code_param = ldpc_init(HRA, mod_order); + + % generate payload data bytes and checksum + + data = floor(rand(1,256)*256); + %data = zeros(1,256); + checksum = crc16(data); + data = [data hex2dec(checksum(3:4)) hex2dec(checksum(1:2))]; + + % unpack bytes to bits and LPDC encode + + mask = 2.^(7:-1:0); % MSB to LSB unpacking to match python tx code. + unpacked_data = []; + for b=1:length(data) + unpacked_data = [unpacked_data bitand(data(b), mask) > 0]; + end + codeword = [ldpc_encode(code_param, unpacked_data) 0 0 0 0]; % pad with 0s to get integer number of bytes + + % pack back into bytes to match python code + + lpacked_codeword = length(codeword)/8; + packed_codeword = zeros(1,lpacked_codeword); + for b=1:lpacked_codeword + st = (b-1)*8 + 1; + packed_codeword(b) = sum(codeword(st:st+7) .* mask); + end + + % generate header bits + + header = [hex2dec('55')*ones(1,16) hex2dec('ab') hex2dec('cd') hex2dec('ef') hex2dec('01')]; + + % now construct entire unpacked frame + + packed_frame = [header packed_codeword]; + mask = 2.^(0:7); % LSB to MSB packing for header + lpacked_frame = length(packed_frame); + frame = []; + for b=1:lpacked_frame + frame = [frame bitand(packed_frame(b), mask) > 0]; + end + + % insert rs232 framing bits + + frame_rs232 = []; + for b=1:8:length(frame) + frame_rs232 = [frame_rs232 0 frame(b:b+7) 1]; + end + + %printf("codeword: %d unpacked_header: %d frame: %d frame_rs232: %d \n", length(codeword), length(unpacked_header), length(frame), length(frame_rs232)); +endfunction + + +% calculates and compares the checksum of a SSTV frame, that has RS232 +% start and stop bits + +function checksum_ok = sstv_checksum(frame_rs232) + l = length(frame_rs232); + expected_l = (256+2)*10; + assert(l == expected_l); + + % extract rx bytes + + rx_data = zeros(1,256); + mask = 2.^(0:7); % LSB to MSB + k = 1; + for i=1:10:expected_l + rx_bits = frame_rs232(i+1:i+8); + rx_data(k) = sum(rx_bits .* mask); + k++; + end + + % calc rx checksum and extract tx checksum + + rx_checksum = crc16(rx_data(1:256)); + tx_checksum = sprintf("%02X%02X", rx_data(258), rx_data(257)); + %printf("tx_checksum: %s rx_checksum: %s\n", tx_checksum, rx_checksum); + checksum_ok = strcmp(tx_checksum, rx_checksum); +endfunction diff --git a/codec2/branches/0.7/octave/ldpc_gen_h_file.m b/codec2/branches/0.7/octave/ldpc_gen_h_file.m new file mode 100644 index 00000000..edda8155 --- /dev/null +++ b/codec2/branches/0.7/octave/ldpc_gen_h_file.m @@ -0,0 +1,72 @@ +% ldpc_gen_h_file.m +% David Rowe Sep 2015 +% +% Create a C include file for use in mpdecode.c C cmd line LDPC decoder + +function ldpc_gen_h_file(code_param, max_iterations, decoder_type, input_decoder_c, x_hat, detected_data) + + f = fopen(code_param.c_include_file, "wt"); + + fprintf(f, "/*\n FILE....: %s\n\n Static arrays for LDPC codec, generated", code_param.c_include_file); + fprintf(f, "\n ldpc_gen_h_file.m.\n\n*/\n\n"); + + fprintf(f,"#define NUMBERPARITYBITS %d\n", rows(code_param.H_rows)); + fprintf(f,"#define MAX_ROW_WEIGHT %d\n", columns(code_param.H_rows)); + fprintf(f,"#define CODELENGTH %d\n", code_param.symbols_per_frame); + fprintf(f,"#define NUMBERROWSHCOLS %d\n", rows(code_param.H_cols)); + fprintf(f,"#define MAX_COL_WEIGHT %d\n", columns(code_param.H_cols)); + fprintf(f,"#define DEC_TYPE %d\n", decoder_type); + fprintf(f,"#define MAX_ITER %d\n", max_iterations); + + fprintf(f,"\ndouble H_rows[] = {\n"); + + % clock out 2D array to linear C array in row order .... + + [r c] = size(code_param.H_rows); + for j=1:c + for i=1:r + fprintf(f, "%d", code_param.H_rows(i,j)); + if (i == r) && (j ==c) + fprintf(f,"\n};\n"); + else + fprintf(f,", "); + end + end + end + + fprintf(f,"\ndouble H_cols[] = {\n"); + [r c] = size(code_param.H_cols); + for j=1:c + for i=1:r + fprintf(f, "%d", code_param.H_cols(i,j)); + if (i == r) && (j == c) + fprintf(f,"\n};\n"); + else + fprintf(f,", "); + end + end + end + + fprintf(f,"\ndouble input[] = {\n"); + for i=1:length(input_decoder_c) + fprintf(f, "%.17g", input_decoder_c(i)); + if i == length(input_decoder_c) + fprintf(f,"\n};\n"); + else + fprintf(f,", "); + end + end + + fprintf(f,"\nchar detected_data[] = {\n"); + for i=1:length(detected_data) + fprintf(f, "%d", detected_data(i)); + if i == length(detected_data) + fprintf(f,"\n};\n"); + else + fprintf(f,", "); + end + end + + fclose(f); +end + diff --git a/codec2/branches/0.7/octave/ldpc_qpsk.m b/codec2/branches/0.7/octave/ldpc_qpsk.m new file mode 100644 index 00000000..4124b452 --- /dev/null +++ b/codec2/branches/0.7/octave/ldpc_qpsk.m @@ -0,0 +1,458 @@ +% ldpc_qpsk.m +% +% David Rowe 18 Dec 2013 +% +% Similar to ldpc_short.m, but derived from ldpcut.m and uses QPSK and +% CML 2D functunctions and QPSK. Probably should combine this and +% ldpc_short.m some day. + +% Our LDPC library + +ldpc; +qpsk; +gp_interleaver; + + +function sim_out = run_simulation(sim_in) + + % Note this is effective Eb/No of payload data bits, sorta thing we + % plot on BER versus Eb/No graphs of decoded data. So if we have a + % rate 1/2 code, each codeword bit will have Eb/No - 3dB. + + EbNodBvec = sim_in.EbNodBvec; + + % for wimax code frame size specifies code + + if isfield(sim_in, "framesize") + framesize = sim_in.framesize; + rate = sim_in.rate; + end + + Ntrials = sim_in.Ntrials; + verbose = sim_in.verbose; + if isfield(sim_in, "hf_en") + hf_en = sim_in.hf_en; + else + hf_en = 0; + end + ldpc_code = sim_in.ldpc_code; + interleave_en = sim_in.interleave_en; + + % Init LDPC code ------------------------------------ + + mod_order = 4; bps = 2; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + if ldpc_code == 1 + code_param = ldpc_init_wimax(rate, framesize, modulation, mod_order, mapping); + end + if ldpc_code == 0 + load HRA_112_112.txt + [code_param framesize rate] = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping); + end + if ldpc_code == 2 + load('H2064_516_sparse.mat'); + HRA = full(HRA); + [code_param framesize rate] = ldpc_init_user(HRA, modulation, mod_order, mapping); + end + if ldpc_code == 3 + load('h0p25d.mat'); + %HRA = full(HRA); + [code_param framesize rate] = ldpc_init_user(H, modulation, mod_order, mapping); + end + + % set up optional HF (multipath) model ------------------------------------ + + % signal is arranged as Nc parallel carriers. Nc is chosen such + % that payload data rate is 700 bits/s. So for higher rate codes Nc + % will be smaller. + + Rs = 50; + vocoder_bps = 700; raw_bps = vocoder_bps/rate; + Nc = round(raw_bps/(Rs*bps)); + Tp = (framesize/Nc)/Rs; Tp_codec2 = 0.04; + fading = ones(1,Ntrials*code_param.code_bits_per_frame/bps); + + printf("framesize: %d rate: %3.2f Nc: %d\n", framesize, rate, Nc); + + if hf_en + + % We assume symbols spread acroos Nc OFDM carriers + + dopplerSpreadHz = 1.0; path_delay = 1E-3*Rs; + + if isfield(sim_in, "dopplerSpreadHz") + dopplerSpreadHz = sim_in.dopplerSpreadHz; + end + if isfield(sim_in, "path_delay") + path_delay = sim_in.path_delay; + end + printf("Doppler Spread: %3.2f Hz Path Delay: %3.2f symbols\n", dopplerSpreadHz, path_delay); + + % reset seed so we get same fading channel on every simulation + + randn('seed',1); + + Ns = Ntrials*code_param.code_bits_per_frame/bps; + Nr = ceil(Ns/Nc); + hf_model = zeros(Nr,Nc); + + % note we ask for 10% more samples than we need, as + % doppler_spread() function can sometimes return slightly less + % than we need due to round off + + spread1 = doppler_spread(dopplerSpreadHz, Rs, Nr*1.1); + spread2 = doppler_spread(dopplerSpreadHz, Rs, Nr*1.1); + spread1 = spread1(1:Nr); + spread2 = spread2(1:Nr); + hf_gain = 1.0/sqrt(var(spread1)+var(spread2)); + end + + % ---------------------------------- + % run simulation at each Eb/No point + % ---------------------------------- + + for ne = 1:length(EbNodBvec) + randn('seed',1); + rand('seed',1); + + % Given Eb/No of payload data bits, work out Es/No we need to + % apply to each channel symbol: + % + % i) Each codeword bit gets noise: Eb/No - 3 (for a rate 1/2 code) + % ii) QPSK means two bits/symbol.: Es/No = Eb/No + 3 + % + % -> which neatly cancel out ...... (at least for rate 1/2) + + EsNodB = EbNodBvec(ne) + 10*log10(rate) + 10*log10(bps); + EsNo = 10^(EsNodB/10); + variance = 1/EsNo; + hf_r = 1; + + Tbits = Terrs = Ferrs = Terrs_raw = Tbits_raw = 0; + + tx_bits = []; + tx_symbols = []; + rx_symbols = []; + + % Encode a bunch of frames + + for nn=1:Ntrials + atx_bits = round(rand( 1, code_param.data_bits_per_frame)); + tx_bits = [tx_bits atx_bits]; + [tx_codeword atx_symbols] = ldpc_enc(atx_bits, code_param); + if interleave_en + atx_symbols = gp_interleave(atx_symbols); + end + tx_symbols = [tx_symbols atx_symbols]; + end + + rx_symbols = tx_symbols; + + % Optional HF (multipath) channel model + + if hf_en + + % Simplified rate Rs OFDM simulation model that doesn't + % include ISI, just freq filtering. We assume perfect phase + % estimation so it's just amplitude distortion. We distribute + % symbols across Nc carriers + + Ns = length(tx_symbols); + w = (1:Nc)*2*pi; + rx_symbols = [rx_symbols zeros(1,Nr*Nc-Ns)]; % pad out to integer number of rows + + for r=1:Nr + for c=1:Nc + hf_model(hf_r,c) = hf_gain*(spread1(hf_r) + exp(-j*w(c)*path_delay)*spread2(hf_r)); + rx_symbols(Nc*(r-1)+c) *= abs(hf_model(hf_r,c)); + fading(Nc*(r-1)+c) = abs(hf_model(hf_r,c)); + end + hf_r++; + end + rx_symbols = rx_symbols(1:Ns); % remove padding + end + + % Add AWGN noise, 0.5 factor splits power evenly between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,length(tx_symbols)) + j*randn(1,length(tx_symbols))); + rx_symbols += noise; + + % Decode a bunch of frames + + rx_bits_log = []; error_positions_log = []; + Nerrs_raw_log = []; + + for nn = 1: Ntrials + st = (nn-1)*code_param.symbols_per_frame + 1; + en = (nn)*code_param.symbols_per_frame; + + % coded + + arx_symbols = rx_symbols(st:en); + afading = fading(st:en); + if interleave_en + arx_symbols = gp_deinterleave(arx_symbols); + afading = gp_deinterleave(afading); + end + + arx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_symbols, EsNo, afading); + st = (nn-1)*code_param.data_bits_per_frame + 1; + en = (nn)*code_param.data_bits_per_frame; + arx_bits = arx_codeword(1:code_param.data_bits_per_frame); + error_positions = xor(arx_bits, tx_bits(st:en)); + error_positions_log = [error_positions_log error_positions]; + Nerrs = sum( error_positions); + rx_bits_log = [rx_bits_log arx_bits]; + + % uncoded - to est raw BER compare first half or received frame to tx_bits as code is systematic + + raw_rx_bits = []; + for s=1:code_param.symbols_per_frame*rate + raw_rx_bits = [raw_rx_bits qpsk_demod(arx_symbols(s))]; + end + Nerrs_raw = sum(xor(raw_rx_bits, tx_bits(st:en))); + Nbits_raw = code_param.data_bits_per_frame; + Nerrs_raw_log = [Nerrs_raw_log Nerrs_raw]; + + if verbose == 2 + % print "." if frame decoded without errors, 'x' if we can't decode + + if Nerrs > 0, printf('x'), else printf('.'), end + if (rem(nn, 50)==0), printf('\n'), end + end + + if Nerrs > 0, Ferrs = Ferrs + 1; end + Terrs += Nerrs; + Tbits += code_param.data_bits_per_frame; + Terrs_raw += Nerrs_raw; + Tbits_raw += Nbits_raw; + end + + % Alternative Codec 2 packet rate measurement indep of framesize + + Nerrs_codec2_log = []; Ncodecpacketsize = 28; + Perrs = 0; Npackets = floor(length(tx_bits)/Ncodecpacketsize); + for p=1:Ncodecpacketsize:Npackets*Ncodecpacketsize + Nerrs = sum(xor(tx_bits(p:p+Ncodecpacketsize-1), rx_bits_log(p:p+Ncodecpacketsize-1))); + if Nerrs + Perrs++; + end + Nerrs_codec2_log = [Nerrs_codec2_log Nerrs]; + end + + if verbose + printf("\nCoded EbNodB: %3.2f BER: %4.3f Tbits: %6d Terrs: %6d FER: %4.3f Tframes: %d Ferrs: %d\n", + EbNodBvec(ne), Terrs/Tbits, Tbits, Terrs, Ferrs/Ntrials, Ntrials, Ferrs); + EbNodB_raw = EbNodBvec(ne) + 10*log10(rate); + printf("Raw EbNodB..: %3.2f BER: %4.3f Tbits: %6d Terrs: %6d\n", + EbNodB_raw, Terrs_raw/Tbits_raw, Tbits_raw, Terrs_raw); + printf("Codec 2 PER: %5.4f Npackets: %d Perrs: %d\n", Perrs/Npackets, Npackets, Perrs); + end + + sim_out.rate = rate; + sim_out.BER(ne) = Terrs/Tbits; + sim_out.PER(ne) = Perrs/Npackets; + sim_out.error_positions = error_positions_log; + + if hf_en && (verbose > 1) + figure(2); clf; + plot(real(rx_symbols(Ns/2:Ns)), imag(rx_symbols(Ns/2:Ns)), '+'); + axis([-2 2 -2 2]); + title('Scatter') + + figure(3); clf; + subplot(211); + stem((1:Ntrials)*Tp, Nerrs_raw_log); + subplot(212); + stem((1:Npackets)*Tp_codec2, Nerrs_codec2_log); + + figure(4); clf; + + % limit mesh plot to Np points to plot quickly + + Np = 500; + step = ceil(hf_r/Np); + mesh(1:Nc, (1:step:hf_r-1)/Rs, abs(hf_model(1:step:hf_r-1,:))) + title('HF channel amplitude'); + xlabel('Carrier'); + ylabel('Time (s)'); + + figure(5) + subplot(211); plot((1:hf_r-1)/Rs, abs(spread1(1:hf_r-1))); + subplot(212); plot((1:hf_r-1)/Rs, abs(spread2(1:hf_r-1))); + title('HF spreading function amplitudes') + end + end + +endfunction + + +% --------------------------------------------------------------------------------- +% Run a bunch of trials at just one EbNo point +% --------------------------------------------------------------------------------- + +function run_single(Nbits=700*10, EbNodB=9, hf_en=0, ldpc_code=1, framesize=576, interleave_en=0, error_pattern_filename) + sim_in.ldpc_code = ldpc_code; + + if sim_in.ldpc_code == 0 + % Our HRA short LDPC code + sim_in.rate=0.5; + sim_in.framesize=448*4+448; + end + if sim_in.ldpc_code == 1 + % CML wimax codes + sim_in.rate = 0.5; + sim_in.framesize = framesize; + end + if sim_in.ldpc_code == 2 + sim_in.rate=0.8; + sim_in.framesize=2064+516; + end + if sim_in.ldpc_code == 3 + sim_in.rate=0.25; + sim_in.framesize=2064+516; + end + + sim_in.verbose = 2; + sim_in.Ntrials = ceil(Nbits/(sim_in.framesize*sim_in.rate)); + sim_in.EbNodBvec = EbNodB; + sim_in.hf_en = hf_en; + sim_in.interleave_en = interleave_en; + + sim_out = run_simulation(sim_in); + + if nargin == 7 + fep = fopen(error_pattern_filename, "wb"); + fwrite(fep, sim_out.error_positions, "short"); + fclose(fep); + end + +end + +% --------------------------------------------------------------------------------- +% Lets draw some Eb/No versus BER curves +% --------------------------------------------------------------------------------- + +function plot_curves(Nbits=700*60) + sim_in.EbNodBvec = -2:12; + sim_in.verbose = 2; + sim_in.interleave_en = 1; + + % Low rate 0.25 VK5DSP code + + sim_in.ldpc_code = 3; + sim_in.rate = 0.25; + sim_in.framesize = 448*4+448; + sim_in.Ntrials = floor(Nbits/(sim_in.framesize*sim_in.rate)); + + sim_in.hf_en = 0; sim_out_awgn_low = run_simulation(sim_in); + sim_in.hf_en = 1; sim_out_hf_low = run_simulation(sim_in); + + % Wimax code + + sim_in.ldpc_code = 1; + sim_in.rate = 0.5; + sim_in.framesize = 576*4; + sim_in.Ntrials = floor(Nbits/(sim_in.framesize*sim_in.rate)); + + sim_in.hf_en = 0; sim_out_awgn_wimax = run_simulation(sim_in); + sim_in.hf_en = 1; sim_out_hf_wimax = run_simulation(sim_in); + + % Our short code from VK5DSP + + sim_in.ldpc_code = 0; + sim_in.rate = 0.5; + sim_in.framesize = 224; + sim_in.Ntrials = floor(Nbits/(sim_in.framesize*sim_in.rate)); + + sim_in.hf_en = 0; sim_out_awgn_short = run_simulation(sim_in); + sim_in.hf_en = 1; sim_out_hf_short = run_simulation(sim_in); + + % Rate 0.8 Wenet code from VK5DSP + + sim_in.ldpc_code = 2; + sim_in.rate = 0.8; + sim_in.framesize = 2064+512; + sim_in.Ntrials = floor(Nbits/(sim_in.framesize*sim_in.rate)); + + sim_in.hf_en = 0; sim_out_awgn_wenet = run_simulation(sim_in); + sim_in.hf_en = 1; sim_out_hf_wenet = run_simulation(sim_in); + + % plots ------------------------- + + EbNodB = sim_in.EbNodBvec; + uncoded_awgn_ber_theory = 0.5*erfc(sqrt(10.^(EbNodB/10))); + + EbNoLin = 10.^(EbNodB/10); + uncoded_hf_ber_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + figure(1) + clf + semilogy(EbNodB, uncoded_awgn_ber_theory,'r-+;AWGN Uncoded;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(EbNodB, uncoded_hf_ber_theory,'r-o;HF Uncoded;','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_wimax.BER+1E-10,'g-+;AWGN LDPC (2304,1152);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_wimax.BER+1E-10,'g-o;HF LDPC (2304,1152);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_short.BER+1E-10,'b-+;AWGN LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_short.BER+1E-10,'b-o;HF LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_wenet.BER+1E-10,'c-+;AWGN LDPC (2576,2064);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_wenet.BER+1E-10,'c-o;HF LDPC (2576,2064);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_low.BER+1E-10,'k-+;AWGN LDPC (1792,448);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_low.BER+1E-10,'k-o;HF LDPC (1792,448);','markersize', 10, 'linewidth', 2); + hold off; + grid('minor') + xlabel('Eb/No (dB)') + ylabel('BER') + axis([min(EbNodB) max(EbNodB) 1E-3 5E-1]) + legend('boxoff') + epsname = sprintf("ldpc_qpsk_ber.eps"); + print('-deps', '-color', epsname) + + uncoded_awgn_per_theory = 1 - (1-uncoded_awgn_ber_theory).^28; + uncoded_hf_per_theory = 1 - (1-uncoded_hf_ber_theory).^28; + + figure(2) + clf + semilogy(EbNodB, uncoded_awgn_per_theory,'r-+;AWGN Uncoded;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(EbNodB, uncoded_hf_per_theory,'r-o;HF Uncoded;','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_wimax.PER+1E-10,'g-+;AWGN LDPC (2304,1152);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_wimax.PER+1E-10,'g-o;HF LDPC (2304,1152);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_short.PER+1E-10,'b-+;AWGN LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_short.PER+1E-10,'b-o;HF LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_wenet.PER+1E-10,'c-+;AWGN LDPC (2576,2064);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_wenet.PER+1E-10,'c-o;HF LDPC (2576,2064);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_awgn_low.PER+1E-10,'k-+;AWGN LDPC (1792,448);','markersize', 10, 'linewidth', 2); + semilogy(EbNodB, sim_out_hf_low.PER+1E-10,'k-o;HF LDPC (1792,448);','markersize', 10, 'linewidth', 2); + hold off; + grid('minor') + xlabel('Eb/No (dB)') + ylabel('PER') + axis([min(EbNodB) max(EbNodB) 1E-2 1]) + legend('boxoff') + legend("location", "southwest"); + epsname = sprintf("ldpc_qpsk_per.eps"); + print('-deps', '-color', epsname) +end + + +% --------------------------------------------------------------------------------- +% Start simulations here +% --------------------------------------------------------------------------------- + +more off; +format; + +init_cml('/home/david/Desktop/cml/'); + +%run_single(Nbits=700*5, EbNo=6, hf_en=1, ldpc_code=3, framesize=576*4, 1) +plot_curves(700*60); + + + diff --git a/codec2/branches/0.7/octave/ldpc_short.m b/codec2/branches/0.7/octave/ldpc_short.m new file mode 100644 index 00000000..38f45450 --- /dev/null +++ b/codec2/branches/0.7/octave/ldpc_short.m @@ -0,0 +1,558 @@ +% ldpc_short.m +% +% David Rowe Mar 2017 +% Based on Bill Cowley's LDPC simulations +% +% Octave simulation of BPSK with short LDPC codes developed by Bill. First step +% in use of LDPC codes with FreeDV and Codec 2 700C. BPSK makes life a bits easier +% for simulation +% +% NOTE: You will need to set the CML path in the call to init_cml() below +% for you CML install. See lpdc.m for instructions on how to install +% CML library + +1; + +gp_interleaver; + +function init_cml(path_to_cml) + currentdir = pwd; + + if exist(path_to_cml, 'dir') == 7 + cd(path_to_cml) + CmlStartup + cd(currentdir); + else + printf("\n---------------------------------------------------\n"); + printf("Can't start CML in path: %s\n", path_to_cml); + printf("See CML path instructions at top of this script\n"); + printf("-----------------------------------------------------\n\n"); + assert(0); + end +end + + +function sim_out = run_sim(sim_in, HRA, Ntrials) + + rand('seed',1); + randn('seed',1); + + % Note this is effective Eb/No of payload data bits, sorta thing we + % plot on BER versus Eb/No graphs of decoded data. So if we have a + % rate 1/2 code, each codeword bit will have Eb/No - 3dB. + + EbNovec = sim_in.EbNovec; + + genie_Es = sim_in.genie_Es; + code = sim_in.code; + hf_en = sim_in.hf_en; + verbose = sim_in.verbose; + + if isfield(sim_in, "interleave_en") + interleave_en = sim_in.interleave_en; + interleave_frames = sim_in.interleave_frames; + else + interleave_en = 0; + interleave_frames = 1; + end + + % default number of carriers for HF model, we fiddle with this a bit + % for different FEC schemes + + Nc = 28; + + % set up for different FEC, get roughly the same frame size so for + % HF channels the simulation runs over roughly the same time + + if strcmp(code, 'ldpc') + [numr numc] = size(HRA); + rate = (numc-numr)/numc; + modulation = 'BPSK'; + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + [H_rows, H_cols] = Mat2Hrows(HRA); + code_param.H_rows = H_rows; + code_param.H_cols = H_cols; + code_param.P_matrix = []; + code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); + code_param.code_bits_per_frame = numc; + Ncodewordsperframe = interleave_frames*224/numc; + framesize = Ncodewordsperframe*numc; + end + + if strcmp(code, 'golay') + rate = 0.5; + code_param.data_bits_per_frame = 12; + code_param.code_bits_per_frame = 24; + + % one Golay (24,12) codeword per row + + Nc = 24; + Ncodewordsperframe = 9; + framesize = Nc*Ncodewordsperframe; + end + + if strcmp(code, 'diversity') + rate = 0.5; + code_param.data_bits_per_frame = Nc/2; + code_param.code_bits_per_frame = Nc; + Ncodewordsperframe = 8; + framesize = Nc*Ncodewordsperframe; + end + + Rs = 50; Tp = (framesize/Nc)/Rs; Tp_codec2 = 0.04; + + % we are using BPSK here + + mod_order = 2; + bps = code_param.bits_per_symbol = log2(mod_order); + + % init HF model + + if hf_en + + % some typical values, assume symbols spread across Nc OFDM carriers + + dopplerSpreadHz = 1; path_delay = 1E-3*Rs; + + nsymb = Ntrials*framesize*bps; + spread1 = doppler_spread(dopplerSpreadHz, Rs, 1.1*ceil(nsymb/Nc)); + spread2 = doppler_spread(dopplerSpreadHz, Rs, 1.1*ceil(nsymb/Nc)); + hf_gain = 1.0/sqrt(var(spread1)+var(spread2)); + % printf("nsymb: %d lspread1: %d\n", nsymb, length(spread1)); + hf_model = zeros(ceil(nsymb/Nc),Nc); + end + + % -------------------------------------------------------------------- + % Sun a simulation for every EbNovec point + %--------------------------------------------------------------------- + + for ne = 1:length(EbNovec) + + % Given Eb/No of payload data bits, work out Es/No we need to + % apply to each codeword symbol, e.g. for rate 1/2 code: + % + % Es/No = Eb/No - 3 dB + + EbNodB = EbNovec(ne); + EsNodB = EbNodB + 10*log10(code_param.bits_per_symbol*rate); + EsNo = 10^(EsNodB/10); + + % reset Hf channel index here so each run gets exactly the same HF channel + + hf_r = 1; + + % bunch of counters and logs + + Terrs = 0; Tbits = 0; Ferrs = 0; Terrs_raw = Tbits_raw = 0; + r_log = []; Nerrs_log = []; Nerrs_raw_log = []; + tx_bits_log = rx_bits_log = []; + + for nn = 1: Ntrials + + % Each trial is one complete frame - OK first set up frame to tx + + codeword = tx_bits = []; + + if strcmp(code, 'ldpc') + for f=1:Ncodewordsperframe + data = round( rand( 1, code_param.data_bits_per_frame ) ); + tx_bits = [tx_bits data]; + codeword = [codeword LdpcEncode(data, code_param.H_rows, code_param.P_matrix) ]; + end + if interleave_en + codeword = gp_interleave(codeword); + end + end + + if strcmp(code, 'golay') + for f=1:Ncodewordsperframe + data = round( rand( 1, code_param.data_bits_per_frame ) ); + tx_bits = [tx_bits data]; + codeword = [codeword egolayenc(data)]; + end + end + + if strcmp(code, 'diversity') + for f=1:Ncodewordsperframe + data = round( rand( 1, code_param.data_bits_per_frame ) ); + tx_bits = [tx_bits data]; + codeword = [codeword data data]; + end + end + + tx_bits_log = [tx_bits_log tx_bits]; + + Nsymb = code_param.code_bits_per_frame/bps; + + % modulate + + s = 1 - 2 * codeword; + Ns = code_param.symbols_per_frame = length(s); + + if hf_en + + % Simplified rate Rs OFDM simulation model that doesn't + % include ISI, just freq filtering. We assume perfect phase + % estimation so it's just amplitude distortion. We distribute + % symbols across Nc carriers + + Nr = ceil(length(s)/Nc); + w = (1:Nc)*2*pi; + s = [s zeros(1,Nr*Nc-Ns)]; % pad out to integer number of rows + + for r=1:Nr + for c=1:Nc + hf_model(hf_r,c) = hf_gain*(spread1(hf_r) + exp(-j*w(c)*path_delay)*spread2(hf_r)); + s(Nc*(r-1)+c) *= abs(hf_model(hf_r,c)); + end + hf_r++; + end + s = s(1:Ns); % remove padding + end + + variance = 1/(EsNo); + noise = sqrt(variance/2)*(randn(1,Ns) + j*randn(1,Ns)); + r = s + noise; + + Nr = length(r); + r_log = [r_log r]; + + % raw BER + + detected_data = real(r) < 0; + error_positions = xor(detected_data, codeword); + + Nerrs_raw = sum(error_positions); + Terrs_raw += Nerrs_raw; + Tbits_raw += length(codeword); + Nerrs_raw_log = [Nerrs_raw_log Nerrs_raw]; + + % FEC decoder + + rx_bits = []; + + if strcmp(code, 'ldpc') + if interleave_en + r = gp_deinterleave(r); + end + + % in the binary case the LLRs are just a scaled version of the rx samples ... + % if the EsNo is known -- use the following + + if (genie_Es) + input_decoder_c = 4 * EsNo * r; + else + r = r / mean(abs(r)); % scale for signal unity signal + estvar = var(r-sign(r)); + estEsN0 = 1/(2* estvar); + input_decoder_c = 4 * estEsN0 * r; + end + + for f=1:Ncodewordsperframe + st = (f-1)*code_param.code_bits_per_frame + 1; + en = st + code_param.code_bits_per_frame - 1; + [x_hat, PCcnt] = MpDecode(input_decoder_c(st:en), code_param.H_rows, code_param.H_cols, ... + max_iterations, decoder_type, 1, 1); + Niters = sum(PCcnt!=0); + arx_bits = x_hat(Niters,:); + rx_bits = [rx_bits arx_bits(1:code_param.data_bits_per_frame)]; + + #{ + if isfield(sim_in, "c_include_file") + + % optionally dump code and unit test data to a C header file + + code_param.c_include_file = sim_in.c_include_file; + ldpc_gen_h_file(code_param, max_iterations, decoder_type, input_decoder_c, x_hat, detected_data); + #} + end + + detected_data = detected_data(1:code_param.data_bits_per_frame); + end + + if strcmp(code, 'golay') + for f=1:Ncodewordsperframe + st = (f-1)*code_param.code_bits_per_frame+1; en=st+code_param.code_bits_per_frame-1; + arx_codeword = egolaydec(real(r(st:en)) < 0); + rx_bits = [rx_bits arx_codeword(code_param.data_bits_per_frame+1:code_param.code_bits_per_frame)]; + end + end + + if strcmp(code, 'diversity') + for f=1:Ncodewordsperframe + st = (f-1)*Nc+1; + r_combined = r(st:st+Nc/2-1) + r(st+Nc/2:st+Nc-1); + arx_data = real(r_combined) < 0; + rx_bits = [rx_bits arx_data]; + end + + #{ + % simulate low rate code to mop up errors + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + if Nerrs < 6 + rx_bits = tx_bits; + end + #} + end + + rx_bits_log = [rx_bits_log rx_bits]; + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Nerrs_log = [Nerrs_log Nerrs]; + + if Nerrs>0, Ferrs += 1; end + Terrs = Terrs + Nerrs; + Tbits = Tbits + code_param.data_bits_per_frame*Ncodewordsperframe; + end + + % Alternative Codec 2 packet rate measurement indep of framesize + + Nerrs_codec2_log = []; + Ncodecpacketsize = 28; + Perrs = 0; Npackets = floor(length(tx_bits_log)/Ncodecpacketsize); + for p=1:Ncodecpacketsize:Npackets*Ncodecpacketsize + Nerrs = sum(xor(tx_bits_log(p:p+Ncodecpacketsize-1), rx_bits_log(p:p+Ncodecpacketsize-1))); + if Nerrs + Perrs++; + end + Nerrs_codec2_log = [Nerrs_codec2_log Nerrs]; + end + + printf("Coded EbNo: %3.1f dB BER: %5.4f PER: %5.4f Nbits: %4d Nerrs: %4d Tpackets: %4d Perr: %4d\n", + EbNodB, Terrs/Tbits, Ferrs/ Ntrials, Tbits, Terrs, Ntrials, Ferrs); + EbNodB_raw = EsNodB - 10*log10(code_param.bits_per_symbol); + printf("Raw EbNo..: %3.1f dB BER: %5.4f Nbits: %4d Nerrs: %4d\n", EbNodB_raw, + Terrs_raw/Tbits_raw, Tbits_raw, Terrs_raw); + printf("Codec 2 PER: %5.4f Npackets: %d Perrs: %d\n", Perrs/Npackets, Npackets, Perrs); + + BERvec(ne) = Terrs/Tbits; + PERvec(ne) = Perrs/Npackets; + + sim_out.BERvec = BERvec; + sim_out.PERvec = PERvec; + + error_positions = xor(tx_bits_log, rx_bits_log); + sim_out.error_positions = error_positions; + + if verbose + figure(3); clf; + plot(real(r_log),imag(r_log),'+') + axis([-2 2 -2 2]) + title('Scatter'); + + figure(4); clf; + subplot(211); + stem((1:Ntrials)*Tp, Nerrs_raw_log); + subplot(212); + stem((1:Npackets)*Tp_codec2, Nerrs_codec2_log); + + if hf_en + figure(6); clf; + + % limit mesh plot to Np points to plot quickly + + Np = 500; + step = ceil(hf_r/Np); + mesh(1:Nc, (1:step:hf_r-1)/Rs, abs(hf_model(1:step:hf_r-1,:))) + title('HF channel amplitude'); + xlabel('Carrier'); + ylabel('Time (s)'); + end + + end + end +endfunction + + +function plot_curves(Ntrials=100, hf_en=0) + + if hf_en + epslabel = 'hf'; + else + epslabel = 'awgn'; + end + + sim_in.genie_Es = 1; + sim_in.code = 'ldpc'; + sim_in.hf_en = hf_en; + sim_in.verbose = 0; + + if hf_en + EbNovec = 2:0.5:10; + else + EbNovec = 0:0.5:8; + end + sim_in.EbNovec = EbNovec; + + load HRA_112_112.txt + load HRA_112_56.txt + load HRA_56_56.txt + load HRA_56_28.txt + + printf("HRA_112_112-------------\n"); + sim_out1 = run_sim(sim_in, HRA_112_112, Ntrials); + +#{ + printf("HRA_112_56-------------\n"); + sim_out2 = run_sim(sim_in, HRA_112_56 , Ntrials); +#} + + printf("HRA_56_56-------------\n"); + sim_out3 = run_sim(sim_in, HRA_56_56 , Ntrials*2); +#{ + printf("HRA_56_28-------------\n"); + sim_out4 = run_sim(sim_in, HRA_56_28 , Ntrials*2); + + printf("Golay -------------\n"); + sim_in.code = 'golay'; + sim_out5 = run_sim(sim_in, [], Ntrials); + +#} + printf("Diversity -------------\n"); + sim_in.code = 'diversity'; + sim_out6 = run_sim(sim_in, [], Ntrials); + + if hf_en + Ebvec_theory = 2:0.5:12; + EbNoLin = 10.^(Ebvec_theory/10); + uncoded_BER_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + else + Ebvec_theory = 0:0.5:8; + uncoded_BER_theory = 0.5*erfc(sqrt(10.^(Ebvec_theory/10))); + end + + % need standard packet size to compare + % packet error if bit 0, or bit 1, or bit 2 ..... + % or bit 0 and bit 1 + % no packet error if all bits ok (1-p(0))*(1-p(1)) + % P(packet error) = p(0)+p(1)+.... + + uncoded_PER_theory = 1 - (1-uncoded_BER_theory).^28; + + figure(1); clf; + semilogy(Ebvec_theory, uncoded_BER_theory, 'b+-;BPSK theory;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(EbNovec, sim_out1.BERvec, 'g+-;rate 1/2 HRA 112 112;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out2.BERvec, 'r+-;rate 2/3 HRA 112 56;','markersize', 10, 'linewidth', 2) + semilogy(EbNovec, sim_out3.BERvec, 'c+-;rate 1/2 HRA 56 56;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out4.BERvec, 'k+-;rate 2/3 HRA 56 28;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out5.BERvec, 'm+-;rate 1/2 Golay (24,12);','markersize', 10, 'linewidth', 2) + semilogy(EbNovec, sim_out6.BERvec, 'go-;rate 1/2 Diversity;','markersize', 10, 'linewidth', 2) + hold off; + xlabel('Eb/No') + ylabel('BER') + grid + legend("boxoff"); + axis([min(Ebvec_theory) max(Ebvec_theory) 1E-3 2E-1]); + epsname = sprintf("ldpc_short_%s_ber.eps", epslabel); + print('-deps', '-color', epsname) + + figure(2); clf; + semilogy(Ebvec_theory, uncoded_PER_theory, 'b+-;BPSK theory;','markersize', 10, 'linewidth', 2) + hold on; + semilogy(EbNovec, sim_out1.PERvec, 'g+-;rate 1/2 HRA 112 112;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out2.PERvec, 'r+-;rate 2/3 HRA 112 56;','markersize', 10, 'linewidth', 2) + semilogy(EbNovec, sim_out3.PERvec, 'c+-;rate 1/2 HRA 56 56;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out4.PERvec, 'k+-;rate 2/3 HRA 56 28;','markersize', 10, 'linewidth', 2) + %semilogy(EbNovec, sim_out5.PERvec, 'm+-;rate 1/2 Golay (24,12);','markersize', 10, 'linewidth', 2) + semilogy(EbNovec, sim_out6.PERvec, 'go-;rate 1/2 Diversity;','markersize', 10, 'linewidth', 2) + hold off; + xlabel('Eb/No') + ylabel('PER') + grid + legend("boxoff"); + if hf_en + legend("location", "southwest"); + end + axis([min(Ebvec_theory) max(Ebvec_theory) 1E-2 1]); + epsname = sprintf("ldpc_short_%s_per.eps", epslabel); + print('-deps', '-color', epsname) +endfunction + + +function run_single(bits, code = 'ldpc', channel = 'awgn', EbNodB, interleave=0, error_pattern_filename) + + sim_in.code = code; + load HRA_112_112.txt + HRA = HRA_112_112; + + sim_in.genie_Es = 1; + + sim_in.EbNovec = EbNodB; + if strcmp(channel, 'awgn') + sim_in.hf_en = 0; + else + sim_in.hf_en = 1; + end + + if interleave + sim_in.interleave_en = 1; + sim_in.interleave_frames = interleave; + else + sim_in.interleave_frames = 1; + end + Ntrials = floor(bits/(112*sim_in.interleave_frames)); + sim_in.verbose = 1; + sim_out = run_sim(sim_in, HRA, Ntrials); + + if nargin == 6 + fep = fopen(error_pattern_filename, "wb"); + fwrite(fep, sim_out.error_positions, "short"); + fclose(fep); + end + +endfunction + + +% Used to generate C header file for C port + +function run_c_header + + sim_in.code = 'ldpc'; + load HRA_112_112.txt + data_bits_per_frame = 112; + rate = 0.5; + bits = data_bits_per_frame; + Ntrials = bits/data_bits_per_frame; + sim_in.genie_Es = 1; + sim_in.hf_en = 0; + sim_in.Esvec = 2; + sim_in.c_include_file = "../src/HRA_112_112.h"; + + sim_out = run_sim(sim_in, HRA_112_112, Ntrials); +endfunction + + +% Start simulation here ---------------------------------------------- + +% change this path for your CML installation + +init_cml('/home/david/Desktop/cml'); + +more off; +format; + +% simple single point test + +run_single(700*60, 'ldpc', 'hf', 6, 32) + +% plotting curves (may take a while) + +%plot_curves(0); +%plot_curves(500,1); + +% generating error files + +%run_single(700*10, 'ldpc', 'awgn', 3, 0, 'awgn_3dB_ldpc.err') +%run_single(700*10, 'diversity', 'awgn', 3, 0, 'awgn_3dB_diversity.err') +%run_single(700*10, 'ldpc', 'hf', 10, 0, 'hf_10dB_ldpc.err') +%run_single(700*10, 'diversity', 'hf', 10, 0, 'hf_10dB_diversity.err') + +% generate C header for C port of code + +%run_c_header diff --git a/codec2/branches/0.7/octave/ldpcdec.m b/codec2/branches/0.7/octave/ldpcdec.m new file mode 100644 index 00000000..2607766d --- /dev/null +++ b/codec2/branches/0.7/octave/ldpcdec.m @@ -0,0 +1,300 @@ +% ldpcdec.m +% David Rowe 31 Dec 2013 +% +% LDPC decoder test program, given a file of QPSK symbols (IQIQ floats), +% performs frame sync, decodes, and measures BER. + +function ldpcdec(filename, Eprob) + + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + % Start simulation + + rand('state',1); + + rate = 3/4; + framesize = 576; + + mod_order = 4; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + EsNo = 4; + if (nargin == 1) + Eprob = 0.0; + end + + nbitspervocoderframe = 52; + nvocoderframes = 8; + nbitspermodemframe = 72; + + code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping); + code_param.code_bits_per_frame = 576; + + data = []; + r = []; + load interleaver.txt + interleaver = interleaver + 1; + + Nframes = 100; + uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]; + + Nc = 18; + + % repeat same simulated vocoder data to ease testing + + vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) ); + + % Decoder: Sync with LDPC frames, de-interleave, LDPC decode, strip off UW, measure BER ------- + + mcwfilename = strcat(filename,"_modcodeword.bin"); + fm=fopen(mcwfilename,"rb"); + etfilename = strcat(filename,"_modcodeword_et.bin"); + fet=fopen(etfilename ,"rb"); + epfilename = strcat(filename,".err"); + fep=fopen(epfilename ,"wb"); + printf("Input QPSK symbols: %s\n", mcwfilename); + if (fet == -1) + printf("Input entered track file: none\n"); + else + printf("Input entered track file: %s\n", etfilename); + end + printf("Output error pattern file: %s\n", epfilename); + + mod_uw = build_mod_uw(uw, 2*length(vd)/length(uw)); + + mod_codeword = zeros(1, code_param.code_bits_per_frame/2); + lmod_codeword = code_param.code_bits_per_frame/2; + + Terrs = 0; Trawerrs = 0; Ferrs = 0; Tbits = 0; Tframes = 0; nerr = []; nrawerr = []; + corr = []; n = 0; + sync_state = 0; sync_count = 0; + mod_unpackedmodem_log = []; + sync_state_log = []; + entered_track_log = []; + sig_pwr_log = []; + + symbols = erasures = 0; + + [mod_unpackedmodem_float32, count] = fread(fm,nbitspermodemframe, "float32"); + if (fet == -1) + entered_track = 0; + else + entered_track = fread(fet, 1, "int"); + end + + while (count == nbitspermodemframe) + n++; + + mod_unpackedmodem = mod_unpackedmodem_float32(1:2:nbitspermodemframe) + j*mod_unpackedmodem_float32(2:2:nbitspermodemframe); + mod_unpackedmodem_log = [mod_unpackedmodem_log mod_unpackedmodem]; + %erasures = rand(1,length(mod_unpackedmodem)) < Eprob; + %mod_unpackedmodem(erasures) = 0; + + % keep buffer of one entire codeword + + mod_codeword(1:lmod_codeword-length(mod_unpackedmodem)) = mod_codeword(length(mod_unpackedmodem)+1:lmod_codeword); + mod_codeword(lmod_codeword-length(mod_unpackedmodem)+1:lmod_codeword) = mod_unpackedmodem; + + [uw_sync corr(n)] = look_for_uw(mod_codeword(1:length(mod_uw)), mod_uw); + + next_sync_state = sync_state; + if ((sync_state == 0) && (uw_sync == 1)) + next_sync_state = 1; + sync_count = 0; + end + if ((sync_state == 1) && (entered_track != 0)) + next_sync_state = 0; + end + sync_state = next_sync_state; + sync_state_log = [sync_state_log sync_state]; + entered_track_log = [entered_track_log entered_track]; + + if (sync_state && (sync_count == 0)) + Tframes++; + + % remove UW symbols + + mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2); + mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)]; + + % de-interleave + + tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw); + + % insert known symbols at end of data + + mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ... + ones(1,length(uw)/2) * qpsk_mod([0 0]) ... + tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ]; + + % determine BER stats of raw data before decoding + + raw_bits = zeros(1, code_param.data_bits_per_frame - length(uw)); + for i=1:(code_param.data_bits_per_frame - length(uw))/2 + raw_bits(2*(i-1)+1:2*i) = qpsk_demod(mod_codeword_deinter(i)); + end + error_positions = xor(vd, raw_bits); + Nerrs = sum(error_positions); + Trawerrs += Nerrs; + nrawerr(Tframes) = Nerrs; + + % Determine Es/N for each carrier. For this codeword we assume + % across codeword (currently 320ms) signal is stationary. + % So for each carrier signal level is constant, so we can + % average across all symols of that carrier to get a better + % estimate of the carrier power. The spectral noise density + % No will be the same for the bandwidth of each carrier. So + % we can use noise samples from all symbols together to get + % a better estimate of the noise power. + + sig_pwr(Tframes,:) = zeros(1,Nc); + noise_samples = []; + for n=1:Nc + + % extract a vector of one carrier's symbols for this codeword + % rotate so that decision boundaries are now real and imag axis + + r = mod_codeword(n:Nc:length(mod_codeword)) .* exp(j*pi/4); + + sig_est = mean(abs(r)); + + % The noise is the variance of symbols (samples) about the actual symbol position + % we reflect all symbols into the first quadrant to simplify things, as the actual + % received symbol isn't matter, just the noise around it. We model the received + % symbol based on the estimated signal level. + + refl_symbols = abs(real(r)) + j*abs(imag(r)); + est_symbols = exp(j*pi/4)*sig_est*ones(1,length(r)); + noise_samples = [ noise_samples (est_symbols - refl_symbols)]; + + sig_pwr(Tframes,n) = sig_est .^ 2; + end + noise_pwr(Tframes) = var(noise_samples); + %plot(real(refl_symbols), imag(refl_symbols), '+'); + %hold on; + %plot(real(exp(j*pi/4)*sig_est*ones(1,length(r))), imag(exp(j*pi/4)*sig_est*ones(1,length(r))), 'r+'); + %hold off; + %printf("SNR: %f\n", 10*log10(sig_est*sig_est/noise_pwr(Tframes))); + + % Set erasures for carrier beneath a certain Es/N + + for n=1:Nc + symbols++; + EsN(n) = 10*log10(sig_pwr(Tframes,n)/noise_pwr(Tframes)); + if (EsN(n) < 1) + %mod_codeword(n:Nc:length(mod_codeword)) = 0; + %printf("Tframes: %d n: %d EsN = %3.2fdB\n", Tframes, n, EsN(n)); + erasures++; + end + end + + % De-interleave again with erasures set ---------------------- + + % remove UW symbols + + mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2); + mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)]; + + tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw); + + % insert known symbols at end of data + + mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ... + ones(1,length(uw)/2) * qpsk_mod([0 0]) ... + tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ]; + + % LDPC decode ------------------------------------------------ + + detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, mod_codeword_deinter, EsNo); + + % unpack payload data, removing UW + + vd_rx = detected_data(1:(code_param.data_bits_per_frame - length(uw))); + + % measure coded BER + + error_positions = xor(vd, vd_rx); + Nerrs = sum(error_positions); + if Nerrs>0, fprintf(1,'x'); Ferrs++; , else fprintf(1,'.'), end + Tbits += length(vd); + Terrs += Nerrs; + nerr(Tframes) = Nerrs; + + % save error patterns is simulated vocoder data to disk + + fwrite(fep, error_positions, "short"); + + end + + if (sync_state) + sync_count++; + if (sync_count == 8) + sync_count = 0; + end + end + + % read in one modulated modem frame at a time + + [mod_unpackedmodem_float32, count] = fread(fm, nbitspermodemframe, "float32"); + if (fet == -1) + entered_track = 0; + else + entered_track = fread(fet, 1, "int"); + end + end + + fclose(fep); + + printf("\nFrames: %d bits: %d errors: %d Raw BER = %f Coded BER = %f FER = %f\n", Tframes, Tbits, Terrs, Trawerrs/Tbits, Terrs/Tbits, Ferrs/Tframes); + printf("Symbols: %d Erasures: %d %f\n", symbols, erasures, erasures/symbols); + figure(8) + clf; + [n m] = size(mod_unpackedmodem_log); + plot( real(mod_unpackedmodem_log), imag(mod_unpackedmodem_log), '+') + axis([-2 2 -2 2]); + title('Scatter Diagram'); + + figure(9) + subplot(311) + plot(sync_state_log); + subplot(312) + plot(nrawerr); + subplot(313) + plot(nerr); + + figure(10); + plot(10*log10(sig_pwr(:,3)./noise_pwr(:)),'b'); + hold on; + plot(10+10*log10(noise_pwr(:))); + plot(10+10*log10(sig_pwr(:,3)),'r'); +% for n=2:Nc +% plot(n*10+10*log10(sig_pwr(:,n)./noise_pwr(:,n))); +% plot(n*10+10*log10(sig_pwr(:,n)),'r'); +% end + hold off; + + y = 1:Tframes; + x = 1:Nc; + z = 10*log10(sig_pwr(:,:)./((noise_pwr(:)*ones(1, Nc)))); + %printf("mean SNR = %3.2fdB\n", mean(z)); + figure(11); + imagesc(x,y,z); + figure(12); + mesh(x,y,z); + axis([1 Nc 1 Tframes 5 15]); + +endfunction diff --git a/codec2/branches/0.7/octave/ldpcenc.m b/codec2/branches/0.7/octave/ldpcenc.m new file mode 100644 index 00000000..87df284a --- /dev/null +++ b/codec2/branches/0.7/octave/ldpcenc.m @@ -0,0 +1,125 @@ +% ldpcenc.m +% David Rowe 20 Dec 2013 +% +% LDPC encoder function. Takes a random data pattern, LDPC Encodes and +% inserts Unique Word (UW) sync bits and ouputs this as a packed +% binary file suitable for the Nc=18 carrier FDMDV modulator, +% fdmdv_mod. Also produces a "modulated" output file of QPSK +% symbols, suitable for feeding into ldpcdec for testing. + +function ldpcenc(filename) + + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + % Start simulation + + rand('state',1); + + rate = 3/4; + framesize = 576; + + mod_order = 4; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + nbitspervocoderframe = 52; + nvocoderframes = 8; + nbitspermodemframe = 72; + + code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping); + + data = []; + r = []; + load interleaver.txt + interleaver = interleaver + 1; + + % Encoder: Generate simulated vocoder data + % LPDC encode + % interleave + % insert UW bits + + Nframes = 100; + uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0]; + + % repeat same simulated vocoder data to ease testing + + vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) ); + + % pad data with zeros the size of UW + + vdpad = [vd zeros(1, length(uw))]; + + % LDPC encode + + [codewordpad, s] = ldpc_enc(vdpad, code_param); + code_param.code_bits_per_frame = length(codewordpad); + code_param.symbols_per_frame = length(s); + + % remove padded zeros after encoding to leave room for UW bits (code + % is systematic) + + codeword = [ codewordpad(1:length(vd)) codewordpad((length(vd)+length(uw)+1):length(codewordpad)) ]; + + % interleave, insert UW bits, and pack bits (as C modulator likes packed bits) + + codeword_interleaved = interleave_bits(interleaver, codeword); + codeword_interleaved_uw = [insert_uw(codeword_interleaved(1:length(vd)), uw) codeword_interleaved(length(vd)+1:length(codeword_interleaved)) ]; + packedcodeword = packmsb(codeword_interleaved_uw); + + cwfilename = strcat(filename,"_codeword.bin"); + fc=fopen(cwfilename,"wb"); + for nn = 1: Nframes + fwrite(fc,packedcodeword,"uchar"); + end + fclose(fc); + + %printf("framesize: %d data_bits_per_frame: %d code_bits_per_frame: %d\n", ... + % framesize, code_param.data_bits_per_frame, code_param.code_bits_per_frame); + + printf("Encoded %d LDPC codewords, saved in packed file: %s\n", Nframes, cwfilename); + + % Modulator: Modulate to QPSK symbols ------------------------------------------ + + nbytespackedcodeword=length(packedcodeword); + fc=fopen(cwfilename,"rb"); + mcwfilename = strcat(filename,"_modcodeword.bin"); + fm=fopen(mcwfilename,"wb"); + nbytespackedmodemframe = nbitspermodemframe/8; + n = 0; + + [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar"); + while (count == nbytespackedmodemframe) + n++; + unpackedmodem = unpackmsb(packedmodem); + + ii = 1; + for i=1:2:length(unpackedmodem) + mod_unpackedmodem(ii) = qpsk_mod(unpackedmodem(i:i+1)); + mod_unpackedmodem_float32(i) = real(mod_unpackedmodem(ii)); + mod_unpackedmodem_float32(i+1) = imag(mod_unpackedmodem(ii)); + ii += 1; + end + + fwrite(fm, mod_unpackedmodem_float32, "float32"); + [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar"); + end + fclose(fc); + fclose(fm); + printf("Modulated %d modem frames to file: %s\n", n, mcwfilename); +endfunction + + diff --git a/codec2/branches/0.7/octave/ldpcut.m b/codec2/branches/0.7/octave/ldpcut.m new file mode 100644 index 00000000..cf45bd2d --- /dev/null +++ b/codec2/branches/0.7/octave/ldpcut.m @@ -0,0 +1,221 @@ +% ldpcut.m +% +% David Rowe 18 Dec 2013 +% +% Octave LDPC unit test script using CML library, based on simulation +% by Bill Cowley VK5DSP + +% Libraries we need + +ldpc; +qpsk; + +function sim_out = run_simulation(sim_in) + + % Note this is effective Eb/No of payload data bits, sorta thing we + % plot on BER versus Eb/No graphs of decoded data. So if we have a + % rate 1/2 code, each codeword bit will have Eb/No - 3dB. + + EbNodBvec = sim_in.EbNodBvec; + + framesize = sim_in.framesize; + rate = sim_in.rate; + Ntrials = sim_in.Ntrials; + verbose = sim_in.verbose; + + % Init LDPC code ------------------------------------ + + mod_order = 4; bps = 2; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + code_param = ldpc_init_wimax(rate, framesize, modulation, mod_order, mapping); + + % ---------------------------------- + % run simulation at each Eb/No point + % ---------------------------------- + + for ne = 1:length(EbNodBvec) + randn('seed',1); + rand('seed',1); + + % Given Eb/No of payload data bits, work out Es/No we need to + % apply to each channel symbol: + % + % i) Each codeword bit gets noise: Eb/No - 3 (for a rate 1/2 code) + % ii) QPSK means two bits/symbol.: Es/No = Eb/No + 3 + % + % -> which neatly cancel out ...... (at least for rate 1/2) + + EsNodB = EbNodBvec(ne) + 10*log10(rate) + 10*log10(bps); + EsNo = 10^(EsNodB/10); + variance = 1/EsNo; + + Tbits = Terrs = Ferrs = Terrs_raw = Tbits_raw = 0; + + tx_bits = []; + tx_symbols = []; + rx_symbols = []; + + % Encode a bunch of frames + + for nn=1:Ntrials + atx_bits = round(rand( 1, code_param.data_bits_per_frame)); + tx_bits = [tx_bits atx_bits]; + [tx_codeword atx_symbols] = ldpc_enc(atx_bits, code_param); + tx_symbols = [tx_symbols atx_symbols]; + end + + rx_symbols = tx_symbols; + + % Add AWGN noise, 0.5 factor splits power evenly between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,length(tx_symbols)) + j*randn(1,length(tx_symbols))); + rx_symbols += noise; + + % Decode a bunch of frames + + rx_bits_log = []; + + for nn = 1: Ntrials + st = (nn-1)*code_param.symbols_per_frame + 1; + en = (nn)*code_param.symbols_per_frame; + + % coded + + arx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symbols(st:en), EsNo); + st = (nn-1)*code_param.data_bits_per_frame + 1; + en = (nn)*code_param.data_bits_per_frame; + error_positions = xor(arx_codeword(1:code_param.data_bits_per_frame), tx_bits(st:en)); + Nerrs = sum( error_positions); + rx_bits_log = [rx_bits_log arx_codeword(1:code_param.data_bits_per_frame)]; + + % uncoded - to est raw BER compare first half or received frame to tx_bits as code is systematic + + raw_rx_bits = []; + for s=1:code_param.symbols_per_frame*rate + raw_rx_bits = [raw_rx_bits qpsk_demod(rx_symbols(st+s-1))]; + end + Nerrs_raw = sum(xor(raw_rx_bits, tx_bits(st:en))); + Nbits_raw = code_param.data_bits_per_frame; + + if verbose == 2 + % print "." if frame decoded without errors, 'x' if we can't decode + + if Nerrs > 0, printf('x'), else printf('.'), end + if (rem(nn, 50)==0), printf('\n'), end + end + + if Nerrs > 0, Ferrs = Ferrs + 1; end + Terrs += Nerrs; + Tbits += code_param.data_bits_per_frame; + Terrs_raw += Nerrs_raw; + Tbits_raw += Nbits_raw; + end + + if verbose + printf("\nCoded EbNodB: %3.2f BER: %4.3f Tbits: %6d Terrs: %6d FER: %4.3f Tframes: %d Ferrs: %d\n", + EsNodB, Terrs/Tbits, Tbits, Terrs, Ferrs/Ntrials, Ntrials, Ferrs); + EbNodB_raw = EbNodBvec(ne) + 10*log10(rate); + printf("Raw EbNodB..: %3.2f BER: %4.3f Tbits: %6d Terrs: %6d\n", + EbNodB_raw, Terrs_raw/Tbits_raw, Tbits_raw, Terrs_raw); + end + + sim_out.rate = rate; + sim_out.BER(ne) = Terrs/Tbits; + sim_out.PER(ne) = Ferrs/Ntrials; + end + +endfunction + +% -------------------------------------------------------------------------------- +% START SIMULATIONS +% -------------------------------------------------------------------------------- + +more off; +format; + +% --------------------------------------------------------------------------------- +% Start CML library (see CML set up instructions in ldpc.m) +% --------------------------------------------------------------------------------- + +currentdir = pwd; +addpath '/home/david/Desktop/cml/mat' % assume the source files stored here +cd /home/david/Desktop/cml +CmlStartup % note that this is not in the cml path! +cd(currentdir) + + +% --------------------------------------------------------------------------------- +% 1/ Simplest possible one frame simulation +% --------------------------------------------------------------------------------- + +printf("\nTest 1\n------\n"); + +mod_order = 4; +modulation = 'QPSK'; +mapping = 'gray'; +demod_type = 0; +decoder_type = 0; +max_iterations = 100; + +framesize = 576*2; % CML library has a bunch of different framesizes available +rate = 1/2; +code_param = ldpc_init_wimax(rate, framesize, modulation, mod_order, mapping); + +EsNo = 10; % decoder needs an estimated channel EsNo (linear ratio, not dB) + +tx_bits = round(rand(1, code_param.data_bits_per_frame)); +[tx_codeword, qpsk_symbols] = ldpc_enc(tx_bits, code_param); +rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, qpsk_symbols, EsNo); + +errors_positions = xor(tx_bits, rx_codeword(1:framesize*rate)); +Nerr = sum(errors_positions); +printf("Nerr: %d\n\n", Nerr); + + +% --------------------------------------------------------------------------------- +% 2/ Run a bunch of trials at just one EsNo point +% --------------------------------------------------------------------------------- + +printf("Test 2\n------\n"); + +% these are inputs for Wimax mode, e.g. framesize defines code used + +sim_in.rate = 0.5; +sim_in.framesize = 576*4; % long codes smooth over fades but increase latency + +sim_in.verbose = 2; +sim_in.Ntrials = 100; +sim_in.EbNodBvec = 9; +run_simulation(sim_in); + + +% --------------------------------------------------------------------------------- +% 3/ Lets draw some Eb/No versus BER curves +% --------------------------------------------------------------------------------- + +printf("\n\nTest 3\n------\n"); + +sim_in.EbNodBvec = -2:10; +sim_out = run_simulation(sim_in); + +EbNodB = sim_in.EbNodBvec; +uncoded_awgn_ber_theory = 0.5*erfc(sqrt(10.^(EbNodB/10))); + +figure(1) +clf +semilogy(EbNodB, uncoded_awgn_ber_theory,'r-+;AWGN;') +hold on; +semilogy(EbNodB, sim_out.BER+1E-10,'g-+;AWGN LDPC;'); +hold off; +grid('minor') +xlabel('Eb/No (dB)') +ylabel('BER') +axis([min(EbNodB) max(EbNodB) 1E-3 1]) +legend('boxoff') + diff --git a/codec2/branches/0.7/octave/linreg.m b/codec2/branches/0.7/octave/linreg.m new file mode 100644 index 00000000..666b65c6 --- /dev/null +++ b/codec2/branches/0.7/octave/linreg.m @@ -0,0 +1,35 @@ +% linreg.m +% David Rowe April 2015 +% +% Based on: +% http://stackoverflow.com/questions/5083465/fast-efficient-least-squares-fit-algorithm-in-c +% +% finds y = mx + b to best fit n points x and y + +function [m b] = linreg(x,y,n) + sumx = 0.0; % sum of x + sumx2 = 0.0; % sum of x^2 + sumxy = 0.0; % sum of x * y + sumy = 0.0; % sum of y + sumy2 = 0.0; % sum of y**2 + + for i=1:n + sumx += x(i); + sumx2 += x(i)^2; + sumxy += x(i) * y(i); + sumy += y(i); + sumy2 += y(i)^2; + end + + denom = (n * sumx2 - sumx*sumx); + + if denom == 0 + % singular matrix. can't solve the problem. + m = 0; + b = 0; + else + m = (n * sumxy - sumx * sumy) / denom; + b = (sumy * sumx2 - sumx * sumxy) / denom; + end + +endfunction diff --git a/codec2/branches/0.7/octave/load_comp.m b/codec2/branches/0.7/octave/load_comp.m new file mode 100644 index 00000000..b9fa6866 --- /dev/null +++ b/codec2/branches/0.7/octave/load_comp.m @@ -0,0 +1,9 @@ +% load_comp.m +% David Rowe Sep 2015 + +function s = load_comp(fn) + fs=fopen(fn,"rb"); + s = fread(fs,Inf,"float32"); + ls = length(s); + s = s(1:2:ls) + j*s(2:2:ls); +endfunction diff --git a/codec2/branches/0.7/octave/load_hackrf.m b/codec2/branches/0.7/octave/load_hackrf.m new file mode 100644 index 00000000..85bfb73e --- /dev/null +++ b/codec2/branches/0.7/octave/load_hackrf.m @@ -0,0 +1,11 @@ +% load_hackrf.m +% +% David Rowe Oct 2015 + +function s = load_hackrf(fn) + fs = fopen(fn,"rb"); + iq = fread(fs,Inf,"schar"); + fclose(fs); + l = length(iq); + s = iq(1:2:l) + j*iq(2:2:l); +endfunction diff --git a/codec2/branches/0.7/octave/load_raw.m b/codec2/branches/0.7/octave/load_raw.m new file mode 100644 index 00000000..1f7868d4 --- /dev/null +++ b/codec2/branches/0.7/octave/load_raw.m @@ -0,0 +1,8 @@ +% load_raw.m +% David Rowe 7 Oct 2009 + +function s = load_raw(fn) + fs=fopen(fn,"rb"); + s = fread(fs,Inf,"short"); + plot(s) +endfunction diff --git a/codec2/branches/0.7/octave/lpcauto.m b/codec2/branches/0.7/octave/lpcauto.m new file mode 100644 index 00000000..7a5e89e1 --- /dev/null +++ b/codec2/branches/0.7/octave/lpcauto.m @@ -0,0 +1,116 @@ +function [ar,e,k]=lpcauto(s,p,t) +%LPCAUTO performs autocorrelation LPC analysis [AR,E,K]=(S,P,T) +% Inputs: +% s(ns) is the input signal +% p is the order (default: 12) +% t(nf,3) specifies the frames size details: each row specifies +% up to three values per frame: [len anal skip] where: +% len is the length of the frame (default: length(s)) +% anal is the analysis length (default: len) +% skip is the number of samples to skip at the beginning (default: 0) +% If t contains only one row, it will be used repeatedly +% until there are no more samples left in s. +% +% Outputs: +% ar(nf,p+1) are the AR coefficients with ar(1) = 1 +% e(nf) is the energy in the residual. +% sqrt(e) is often called the 'gain' of the filter. +% k(nf,2) gives the first and last sample of the analysis interval + +% Notes: +% +% (1) The first frame always starts at sample s(1) and the analysis window starts at s(t(1,3)+1). +% (2) The elements of t need not be integers. +% (3) The analysis interval is always multiplied by a hamming window +% (4) As an example, if p=3 and t=[10 5 2], then the illustration below shows +% successive frames labelled a, b, c, ... with capitals for the +% analysis regions. Note that the first frame starts at s(1) +% +% a a A A A A A a a a b b B B B B B b b b c c C C C C C c c c d ... +% +% For speech processing, it can be advantageous to restrict the analysis regions +% to time intervals when the glottis is closed. +% +% (5) Frames can overlap: e.g. t=[10 20] will use analysis frames of +% length 20 overlapped by 10 samples. +% (6) For speech processing p should be at least 2*f*l/c where f is the sampling +% frequency, l the vocal tract length and c the speed of sound. For a typical +% male (l=17 cm) this gives f/1000. + +% Copyright (C) Mike Brookes 1997 +% Version: $Id: lpcauto.m 713 2011-10-16 14:45:43Z dmb $ +% +% VOICEBOX is a MATLAB toolbox for speech processing. +% Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 2 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You can obtain a copy of the GNU General Public License from +% http://www.gnu.org/copyleft/gpl.html or by writing to +% Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +s = s(:); % make it a column vector +if nargin < 2 p=12; end; +if nargin < 3 t=length(s); end; +%if nargin < 4 w='ham'; end; +[nf,ng]=size(t); +if ng<2 t=[t t]; end; +if ng<3 t=[t zeros(nf,1)]; end; +if nf==1 + nf=floor(1+(length(s)-t(2)-t(3))/t(1)); + tr=0; +else + tr=1; +end; + +ar=zeros(nf,p+1); +ar(:,1)=1; +e=zeros(nf,1); + +t1=1; +it=1; +nw=-1; +zp=zeros(1,p); +r=(0:p); +for jf=1:nf + k(jf,1) = ceil(t1+t(it,3)); + k(jf,2) = ceil(t1+t(it,3)+t(it,2)-1); + cs = (k(jf,1):k(jf,2)).'; + nc = length(cs); + pp=min(p,nc); + dd=s(cs); + if nc~=nw + % possibly we should have a window whose square integral equals unity + ww=hamming(nc); nw=nc; + y=zeros(1,nc+p); + c=(1:nc)'; + end + wd=dd(:).*ww; % windowed data vector + y(1:nc)=wd; % data vector with p appended zeros + z=zeros(nc,pp+1); % data matrix + % was previously z(:)=y(c(:,ones(1,pp+1))+r(ones(nc,1),1:pp+1)); + z(:)=y(repmat(c,1,pp+1)+repmat(r,nc,1)); + rr=wd'*z; + rm=toeplitz(rr(1:pp)); + rk=rank(rm); + if rk + if rk n + a = a'; + end + m = length(a)-1; + pz = [a,0] - [0 fliplr(a)]; + qz = [a,0] + [0 fliplr(a)]; + angpz = sort(angle(roots(pz))); + angpz = angpz(find(angpz > 0)); + angqz = sort(angle(roots(qz))); + angqz = angqz(find(angqz > 0 & angqz < pi)); + w = zeros(1,m); + j = 1:(m/2); + w(2*j) = angpz'; + w(2*j-1) = angqz'; +endfunction + +% +% Given input Line spectral pair (LSP) parameters of an AR filter, +% this function calculates the corresponding AR filter parameters +% +% Author : Madhukar Budagavi +% + +function a=lsptoa(w) + + [m,n] = size(w); + if m > n + w = w'; + end + m = length(w); + pz = 1; + qz = 1; + for j = 1:(m/2), + pz = conv(pz,[1 -2*cos(w(2*j)) 1]); + qz = conv(qz,[1 -2*cos(w(2*j-1)) 1]); + end + pz = conv([1 -1],pz); + qz = conv([1 1],qz); + a = (pz+qz)/2; + a = a(1:(m+1)); + +endfunction diff --git a/codec2/branches/0.7/octave/lsp_pdf.m b/codec2/branches/0.7/octave/lsp_pdf.m new file mode 100644 index 00000000..4fc1359a --- /dev/null +++ b/codec2/branches/0.7/octave/lsp_pdf.m @@ -0,0 +1,91 @@ +% lsp_pdf.m +% David Rowe 2 Oct 2009 +% Plots histograms (PDF estimates) of LSP training data + +function lsp_pdf(lsp) + [r,c] = size(lsp); + + % LSPs + + figure(1); + clf; + [x,y] = hist(lsp(:,1),100); + plot(y*4000/pi,x,"+;1;"); + hold on; + for i=2:5 + [x,y] = hist(lsp(:,i),100); + legend = sprintf("+%d;%d;",i,i); + plot(y*4000/pi,x,legend); + endfor + for i=6:c + [x,y] = hist(lsp(:,i),100); + legend = sprintf("+%d;%d;",i-5,i); + plot(y*4000/pi,x,legend); + endfor + hold off; + grid; + + % LSP differences + + figure(2); + clf; + subplot(211) + [x,y] = hist(lsp(:,1),100); + plot(y*4000/pi,x,"1;1;"); + hold on; + for i=2:5 + [x,y] = hist(lsp(:,i) - lsp(:,i-1),100); + legend = sprintf("%d;%d;",i,i); + plot(y*4000/pi,x,legend); + endfor + hold off; + grid; + + subplot(212) + [x,y] = hist(lsp(:,6)-lsp(:,5),100); + plot(y*4000/pi,x,"1;6;"); + hold on; + for i=7:c + [x,y] = hist(lsp(:,i) - lsp(:,i-1),100); + legend = sprintf("%d;%d;",i-5,i); + plot(y*4000/pi,x,legend); + endfor + hold off; + grid; + + % LSP differences delta from last frame + + lspd(:,1) = lsp(:,1); + lspd(:,2:10) = lsp(:,2:10) - lsp(:,1:9); + + [m,n] = size(lspd); + lspdd = lspd(5:m,:) - lspd(1:m-4,:); + + figure(3); + clf; + subplot(211) + for i=1:5 + [x,y] = hist(lspdd(:,i),100); + legend = sprintf("%d;%d;",i,i); + plot(y*4000/pi,x,legend); + hold on; + endfor + hold off; + grid; + axis([-200 200 0 35000]); + + subplot(212) + for i=6:10 + [x,y] = hist(lspdd(:,i),100); + legend = sprintf("%d;%d;",i-5,i); + plot(y*4000/pi,x,legend); + hold on; + endfor + hold off; + grid; + axis([-200 200 0 16000]); + + figure(4); + clf; + plot((4000/pi)*(lsp(2:r,3)-lsp(1:r-1,3))) +endfunction diff --git a/codec2/branches/0.7/octave/lspvar.m b/codec2/branches/0.7/octave/lspvar.m new file mode 100644 index 00000000..aa4e245a --- /dev/null +++ b/codec2/branches/0.7/octave/lspvar.m @@ -0,0 +1,57 @@ +% lspvar.m +% David Rowe 8 Feb 2015 +% +% Experiments in reducing LSP variance in order to make quantisation easier + +lsp; +close all; +graphics_toolkit ("gnuplot"); + +function v = det_var(s) + p = 10; + ak=lpcauto(s,p,[160 80]); + [rows cols] = size(ak); + w = zeros(rows,p); + for r=1:rows + w(r,:) = atolsp(ak(r,:)); + end + v = sum(var(w)); + figure; + plot(w) +end + +s=load_raw("../raw/cq_ref.raw"); +det_var(s) + +if 1 + Fs = 8000; + [b a] = cheby2(6,40,[300 2600]/(Fs/2)); + s1 = filter(b,a,s); + det_var(s1) +end + +% + Equalise to remove spectral slope, this reduces variance of spectral +% envelope +% + Can probably get rid of energy for many vectors too, except flat ones? +% + Or have some sort of correlation of gain with peakiness of vectors? +% + Once flattened try slicing out low energy harmonics, like post filter. How +% does this sound? Any artefacts of harmonics coming and going near +% thresholds? +% + BPF as well, it's all abt minimal information. +% + What's left? Look at it. How can it be represented? Look at tol distort, +% what quantiser will deliver that? Just position of clipped peaks? +% + fall back HF mode, no energy, voicing, just spectral information. Diveristy +% compared to FEC? Test with simulation of ideal code. Aux carrier with +% extra information to get 1300-ish quality. Coherent, pilot assisted demod. +% Low PAPR as extra carriers at lower power level. Essentially for free in +% terms of TX power. +% + What is a viable plan to get this going in a mon month or so? +% + Octave equlaisation of input files +% + take model files, simulate quantisation, back to C for synth? +% + Coherent FDM modem port to C + + + + + + diff --git a/codec2/branches/0.7/octave/lspwarp.m b/codec2/branches/0.7/octave/lspwarp.m new file mode 100644 index 00000000..2d2f2c99 --- /dev/null +++ b/codec2/branches/0.7/octave/lspwarp.m @@ -0,0 +1,40 @@ +% lspwarp.m +% David Rowe Sep 2012 +% +% Experimenting with non-linear LSP frequency axis for LSP quantisation +% Plots a scaled mel axis. + +1; + +function mel = freq2mel(f) + mel = 70*log10(1 + f/700); +endfunction + +function freq = mel2freq(m) + freq = 700*(10 ^ (m/70) - 1); +endfunction + +x = []; y = []; + +for freq = 100:25:4000 + mel = freq2mel(freq); + x = [x freq]; + y = [y mel]; +end + +plot(x,y) +grid + +mel_start = floor(freq2mel(100)); +mel_end = floor(freq2mel(4000)); + +x = []; y = []; +for mel=mel_start:mel_end + freq = mel2freq(mel); + x = [x freq]; + y = [y mel]; +end + +hold on; +plot(x,y, '+') +hold off; diff --git a/codec2/branches/0.7/octave/mag_to_phase.m b/codec2/branches/0.7/octave/mag_to_phase.m new file mode 100644 index 00000000..c81ed087 --- /dev/null +++ b/codec2/branches/0.7/octave/mag_to_phase.m @@ -0,0 +1,62 @@ +% mag_to_phase.m +% +% David Rowe Sep 2015 +% +% Slighly modified version of http://www.dsprelated.com/showcode/20.php +% +% Given a magnitude spectrum in dB, returns a minimum-phase phase +% spectra. Both must be sampled at a Nfft. My understanding of this +% is rather dim, but a working example is good place to start! + + +function [phase s] = mag_to_phase(Gdbfk, Nfft = 512, verbose_en = 0) + + Ns = length(Gdbfk); if Ns~=Nfft/2+1, error("confusion"); end + Sdb = [Gdbfk,Gdbfk(Ns-1:-1:2)]; % install negative-frequencies + + S = 10 .^ (Sdb/20); % convert to linear magnitude + s = ifft(S); % desired impulse response + s = real(s); % any imaginary part is quantization noise + tlerr = 100*norm(s(round(0.9*Ns:1.1*Ns)))/norm(s); + if verbose_en + disp(sprintf([' Time-limitedness check: Outer 20%% of impulse ' ... + 'response is %0.2f %% of total rms'],tlerr)); + end + % = 0.02 percent + + if verbose_en + if tlerr>1.0 % arbitrarily set 1% as the upper limit allowed + disp(' Increase Nfft and/or smooth Sdb\n'); + end + end + + c = ifft(Sdb); % compute real cepstrum from log magnitude spectrum + + % Check aliasing of cepstrum (in theory there is always some): + + caliaserr = 100*norm(c(round(Ns*0.9:Ns*1.1)))/norm(c); + if verbose_en + disp(sprintf([' Cepstral time-aliasing check: Outer 20%% of ' ... + 'cepstrum holds %0.2f %% of total rms\n'],caliaserr)); + end + + if verbose_en + if caliaserr>1.0 % arbitrary limit + disp(' Increase Nfft and/or smooth Sdb to shorten cepstrum\n'); + end + end + + % Fold cepstrum to reflect non-min-phase zeros inside unit circle: + + cf = [c(1), c(2:Ns-1)+c(Nfft:-1:Ns+1), c(Ns), zeros(1,Nfft-Ns)]; + + Cf = fft(cf); % = dB_magnitude + j * minimum_phase + + % The maths says we are meant to be using log(x), not 20*log10(x), + % so we need to scale the phase to account for this: + % log(x) = 20*log10(x)/scale; + + scale = (20/log(10)); + phase = imag(Cf)/scale; +endfunction + diff --git a/codec2/branches/0.7/octave/make_hilb.m b/codec2/branches/0.7/octave/make_hilb.m new file mode 100644 index 00000000..35d4e55e --- /dev/null +++ b/codec2/branches/0.7/octave/make_hilb.m @@ -0,0 +1,51 @@ +% make_hilb.m +% David Rowe May 2015 +% +% creates Hilber Transformer FIR coeffs + +graphics_toolkit ("gnuplot"); + +ht_n = 100; +imp = [1 zeros(1,ht_n-1)]; +ht_coeff = fftshift(hilbert(imp)) .* hanning(ht_n)'; + +figure(1) +subplot(211) +plot(real(ht_coeff)) +subplot(212) +plot(imag(ht_coeff)) + +figure(2) +plot(20*log10(abs(fft(ht_coeff)))) + +% test it + +n=1:8000; +w = 2*pi/4; +x = cos(n*w); +figure(3) +y = filter(ht_coeff,1,x); +figure(3) +subplot(211) +plot(y(800:8000)) +subplot(212) +plot(20*log10(abs(fft(y(800:8000))))) + +% save coeffs to a C header file + +f=fopen("../src/ht_coeff.h","wt"); +fprintf(f,"/* Hilbert Transform FIR filter coeffs */\n"); +fprintf(f,"/* Generated by make_hilb Octave script */\n"); + +fprintf(f,"\n#define HT_N %d\n\n", ht_n); + +fprintf(f,"COMP ht_coeff[]={\n"); +for r=1:ht_n + if r < ht_n + fprintf(f, " {%f,%f},\n", real(ht_coeff(r)), imag(ht_coeff(r))); + else + fprintf(f, " {%f,%f}\n};", real(ht_coeff(r)), imag(ht_coeff(r))); + end +end + +fclose(f); diff --git a/codec2/branches/0.7/octave/make_ssbfilt.m b/codec2/branches/0.7/octave/make_ssbfilt.m new file mode 100644 index 00000000..b1bb3474 --- /dev/null +++ b/codec2/branches/0.7/octave/make_ssbfilt.m @@ -0,0 +1,36 @@ +% make_ssbfilt.m +% David Rowe May 2015 +% +% creates SSB filter FIR coeffs + +graphics_toolkit ("gnuplot"); + +ssbfilt_n = 100; +Fs = 8000; + +ssbfilt_coeff = fir2(ssbfilt_n,[0 400 600 2200 2600 4000]/(Fs/2),[0.001 0.001 1 1 0.001 0.001]); + +figure(1) +clf; +h = freqz(ssbfilt_coeff,1,Fs/2); +plot(20*log10(abs(h))) +grid minor + +% save coeffs to a C header file + +f=fopen("../src/ssbfilt_coeff.h","wt"); +fprintf(f,"/* 600 - 2600 Hz FIR filter coeffs */\n"); +fprintf(f,"/* Generated by make_ssbfilt Octave script */\n"); + +fprintf(f,"\n#define SSBFILT_N %d\n\n", ssbfilt_n); + +fprintf(f,"float ssbfilt_coeff[]={\n"); +for r=1:ssbfilt_n + if r < ssbfilt_n + fprintf(f, " %f,\n", ssbfilt_coeff(r)); + else + fprintf(f, " %f\n};", ssbfilt_coeff(r)); + end +end + +fclose(f); diff --git a/codec2/branches/0.7/octave/mancyfsk.m b/codec2/branches/0.7/octave/mancyfsk.m new file mode 100644 index 00000000..a5ac8ccb --- /dev/null +++ b/codec2/branches/0.7/octave/mancyfsk.m @@ -0,0 +1,500 @@ +% mancyfsk.m +% David Rowe October 2015 +% +% Manchester encoded 2FSK & 4FSK simulation. +% +% Attempt to design a FSK waveform that can pass through legacy FM +% radios but still be optimally demodulated by SDRs. It doesn't have +% to be optimally demodulated by legacy radios. Trick is getting it +% to pass through 300-3000Hz audio filters in legacy radios. +% +% [X] code up modulator +% [X] manchester two bit symbols +% [X] plot spectrum +% [X] demodulate using analog FM and ideal demods +% [X] measure BER compared to ideal coherent FSK + +1; + +fm; % analog FM library + + +function states = legacyfsk_init(M,Rs) + Fs = states.Fs = 96000; + states.Rs = Rs; % symbol rate over channel + Ts = states.Ts = Fs/Rs; % symbol period in samples + states.M = M; % mFSK, either 2 or 4 + bpsym = state.Rb = log2(M); % bits per symbol over channel + rate = states.rate = 0.5; % Manchester code rate + nbits = 100; + nbits = states.nbits = 100; % number of payload data symbols/frame + nbits2 = states.nbits2 = nbits/rate; % number of symbols/frame over channel after manchester encoding + nsym = states.nsym = nbits2/log2(M); % number of symbols per frame + nsam = states.nsam = nsym*Ts; + + %printf(" Rs: %d M: %d bpsym: %d nbits: %d nbits2: %d nsym: %d nsam: %d\n", Rs, M, bpsym, nbits, nbits2, nsym, nsam); + + states.fc = states.Fs/4; + if states.M == 2 + states.f(1) = states.fc - Rs/2; + states.f(2) = states.fc + Rs/2; + else + states.f(1) = states.fc - 3*Rs/2; + states.f(2) = states.fc - Rs/2; + states.f(3) = states.fc + Rs/2; + states.f(4) = states.fc + 3*Rs/2; + end +endfunction + + +% test modulator function + +function tx = legacyfsk_mod(states, tx_bits) + Fs = states.Fs; + Ts = states.Ts; + Rs = states.Rs; + f = states.f; + M = states.M; + nsym = states.nsym; + + tx = zeros(Ts*length(tx_bits)/log2(M),1); + tx_phase = 0; + + step = log2(M); + k = 1; + for i=1:step:length(tx_bits) + if M == 2 + tone = tx_bits(i) + 1; + else + tone = (tx_bits(i:i+1) * [2 1]') + 1; + end + tx_phase_vec = tx_phase + (1:Ts)*2*pi*f(tone)/Fs; + tx((k-1)*Ts+1:k*Ts) = 2.0*cos(tx_phase_vec); k++; + tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi; + end + +endfunction + + +function run_sim(sim_in) + + frames = sim_in.frames; + test_frame_mode = sim_in.test_frame_mode; + M = sim_in.M; + Rs = sim_in.Rs; + demod = sim_in.demod; + EbNodB = sim_in.EbNodB; + timing_offset = sim_in.timing_offset; + + % rx timing has been adjusted experimentally + + if Rs == 4800 + if demod == 1 + rx_timing = 4; + else + rx_timing = 0; + end + end + if Rs == 2400 + if demod == 1 + rx_timing = 40; + else + rx_timing = 0; + end + end + + % init fsk modem + + more off + rand('state',1); + randn('state',1); + states = legacyfsk_init(M,Rs); + Fs = states.Fs; + nbits = states.nbits; + nbits2 = states.nbits2; + Ts = states.Ts; + nsam = states.nsam; + rate = states.rate; + + % init analog FM modem + + fm_states.Fs = Fs; + fm_max = fm_states.fm_max = 3E3; + fd = fm_states.fd = 5E3; + fm_states.fc = states.fc; + + fm_states.pre_emp = 0; + fm_states.de_emp = 1; + fm_states.Ts = 1; + fm_states.output_filter = 1; + fm_states = analog_fm_init(fm_states); + [b, a] = cheby1(4, 1, 300/Fs, 'high'); % 300Hz HPF to simulate FM radios + + % init sim states + + rx_bits_buf = zeros(1,2*nbits2); + Terrs = Tbits = 0; + state = 0; + nerr_log = []; + + % set up the channel noise. We have log(M)*rate payload bits/symbol + % we have log2(M) bits/symbol, and rate bits per payload symbol + % TODO: explain this better as Im confused! + + EbNo = 10^(EbNodB/10); + EsNo = EbNo*rate*log2(M); + variance = states.Fs/((states.Rs)*EsNo); + %printf("EbNodB: %3.1f EbNo: %3.2f EsNo: %3.2f\n", EbNodB, EbNo, EsNo); + + % set up the input bits + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, nbits)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, nbits*(frames+1))); + end + if test_frame_mode == 3 + % ...10101... sequence + tx_bits = zeros(1, nbits*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + end + + % Manchester Encoding ----------------------------------------------------------- + + % Manchester encoding, which removes DC term in baseband signal, + % making the waveform friendly to old-school legacy FM radios with + % voiceband filtering. The "code rate" is 0.5, which means we have + % encode one input bit into 2 output bits. The 2FSK encoder takes + % one input bit, the 4FSK encoder two input bits. + + tx_bits_encoded = zeros(1,length(tx_bits)*2); + fsk2_enc = [[1 0]; [0 1]]; + % -1.5 1.5 1.5 -1.5 -0.5 0.5 0.5 -0.5 + % 0 3 3 0 1 2 2 1 + fsk4_enc = [[0 0 1 1]; [1 1 0 0]; [0 1 1 0]; [1 0 0 1]]; + k=1; + if M == 2 + for i=1:2:length(tx_bits_encoded) + input_bit = tx_bits(k); k++; + tx_bits_encoded(i:i+1) = fsk2_enc(input_bit+1,:); + end + else + for i=1:4:length(tx_bits_encoded) + input_bits = tx_bits(k:k+1) * [2 1]'; k+=2; + tx_bits_encoded(i:i+3) = fsk4_enc(input_bits+1,:); + end + end + + % FSK Modulator -------------------------------------------------------------- + + % use ideal FSK modulator (note: need to try using analog FM modulator) + + tx = legacyfsk_mod(states, tx_bits_encoded); + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + timing_offset_samples = round(timing_offset*Ts); + rx = [zeros(timing_offset_samples,1); rx]; + + % Demodulator ---------------------------------------------------------------------------- + + if demod == 1 + % use analog FM demodulator, aka a $40 Baofeng + + [rx_out rx_bb] = analog_fm_demod(fm_states, rx'); + if sim_in.hpf + rx_out_hp = filter(b,a,rx_out); + else + rx_out_hp = rx_out; + end + rx_filt = filter(ones(1,Ts),1,rx_out_hp); + rx_timing_sig = rx_filt; + + % TODO: for 4FSK determine amplitude/decn boundaries, choose closest to demod each symbol + + end + + if demod == 2 + + % optimal non-coherent demod at Rs + + rx_timing_sig = zeros(1,length(rx)); + for m=1:M + phi_vec = (1:length(rx))*2*pi*states.f(m)/Fs; + dc = rx' .* exp(-j*phi_vec); + rx_filt(m,:) = abs(filter(ones(1,Ts),1,dc)); + rx_timing_sig = rx_timing_sig + rx_filt(m,1:length(rx)); + end + end + + % Fine timing estimation ------------------------------------------------------ + + % Estimate fine timing using line at Rs/2 that Manchester encoding provides + % We need this to sync up to Manchester codewords. TODO plot signal and + % timing "line" we extract + + Np = length(rx_timing_sig); + w = 2*pi*(Rs)/Fs; + x = (rx_timing_sig .^ 2) * exp(-j*w*(0:Np-1))'; + norm_rx_timing = angle(x)/(2*pi) - 0.42; + %rx_timing = round(norm_rx_timing*Ts); + %printf("norm_rx_timing: %4.4f rx_timing: %d\n", norm_rx_timing, rx_timing); + + % Max likelihood decoding of Manchester encoded symbols. Search + % through all ML possibilities to extract bits. Use energy (filter + % output sq) + + % Manchester Decoding -------------------------------------------------------- + + if M == 2 + if demod == 1 + + % sample at optimum instant + + [tmp l] = size(rx_filt); + rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l); + + [tmp l] = size(rx_filt_dec); + rx_bits = zeros(1,l); + k = 1; + for i=1:2:l-1 + ml = [rx_filt_dec(i)-rx_filt_dec(i+1) -rx_filt_dec(i)+rx_filt_dec(i+1)]; + [mx mx_ind] = max(ml); + rx_bits(k) = mx_ind-1; k++; + end + end + + if demod == 2 + + % sample at optimum instant + + [tmp l] = size(rx_filt); + rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l); + + [tmp l] = size(rx_filt_dec); + rx_bits = zeros(1,l); + k = 1; + for i=1:2:l-1 + %ml = [rx_filt_dec(2,i)*rx_filt_dec(1,i+1) rx_filt_dec(1,i)*rx_filt_dec(2,i+1)]; + ml = [rx_filt_dec(2,i)+rx_filt_dec(1,i+1) rx_filt_dec(1,i)+rx_filt_dec(2,i+1)]; + [mx mx_ind] = max(ml); + rx_bits(k) = mx_ind-1; k++; + end + end + else % M == 4 + if demod == 1 + % TODO: 4FSK version of demod + rx_bits=tx_bits; + end + if demod == 2 + % sample at optimal instant + + [tmp l] = size(rx_filt); + rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l); + [tmp l] = size(rx_filt_dec); + rx_bits = zeros(1,l); + + k = 1; + fsk4_dec = [[0 0]; [0 1]; [1 0]; [1 1]]; + for i=1:2:l-1 + %ml = [rx_filt_dec(1,i)*rx_filt_dec(4,i+1) rx_filt_dec(4,i)*rx_filt_dec(1,i+1) rx_filt_dec(2,i)*rx_filt_dec(3,i+1) rx_filt_dec(3,i)*rx_filt_dec(2,i+1)]; + ml = [(rx_filt_dec(1,i)+rx_filt_dec(4,i+1)) (rx_filt_dec(4,i)+rx_filt_dec(1,i+1)) (rx_filt_dec(2,i)+rx_filt_dec(3,i+1)) (rx_filt_dec(3,i)+rx_filt_dec(2,i+1))]; + [mx mx_ind] = max(ml); + rx_bits(k:k+1) = fsk4_dec(mx_ind,:); k+=2; + end + end + end + + % useful for getting decoding right + %tx_bits(1:20) + %rx_bits(1:20) + + % Frame sync and BER logic ------------------------------------------------------------- + + st = 1; + for f=1:frames + + % extract nin bits + + nin = nbits; + en = st + nin - 1; + + rx_bits_buf(1:nbits) = rx_bits_buf(nbits+1:2*nbits); + rx_bits_buf(nbits+1:2*nbits) = rx_bits(st:en); + + st += nin; + + % frame sync based on min BER + + if test_frame_mode == 1 + nerrs_min = nbits; + next_state = state; + if state == 0 + for i=1:nbits + error_positions = xor(rx_bits_buf(i:nbits+i-1), test_frame); + nerrs = sum(error_positions); + %printf("i: %d nerrs: %d nerrs_min: %d \n", i, nerrs, nerrs_min); + if nerrs < nerrs_min + nerrs_min = nerrs; + coarse_offset = i; + end + end + if nerrs_min < 3 + next_state = 1; + %printf("%d %d\n", coarse_offset, nerrs_min); + end + end + + if state == 1 + error_positions = xor(rx_bits_buf(coarse_offset:coarse_offset+nbits-1), test_frame); + nerrs = sum(error_positions); + Terrs += nerrs; + Tbits += nbits; + nerr_log = [nerr_log nerrs]; + end + + state = next_state; + + end + end + + if test_frame_mode == 1 + if sim_in.verbose + printf(" demod: %d frames: %d EbNodB: %3.1f Tbits: %d Terrs: %d BER %4.3f\n", demod, frames, EbNodB, Tbits, Terrs, Terrs/Tbits); + else + printf(" EbNodB: %3.1f BER %4.3f\n", EbNodB, Terrs/Tbits); + end + end + + % Bunch O'plots -------------------------------------------------------------- + + close all; + + st = 1; en=20; + + Tx=fft(tx, Fs); + TxdB = 20*log10(abs(Tx(1:Fs/2))); + figure(1) + clf; + plot(TxdB) + axis([1 Fs/2 (max(TxdB)-100) max(TxdB)]) + title('Tx Spectrum'); + + figure(2) + clf + if demod == 1 + subplot(211) + plot(rx_filt(st*Ts:en*Ts)); + title('After integrator'); + subplot(212) + plot(rx_filt_dec(st:en),'+'); + title('Decimated output'); + end + if demod == 2 + subplot(211); + plot(rx_filt(1,st*Ts:en*Ts)); + hold on; + plot(rx_filt(2,st*Ts:en*Ts),'g'); + if M == 4 + plot(rx_filt(3,st*Ts:en*Ts),'c'); + plot(rx_filt(4,st*Ts:en*Ts),'r'); + end + hold off; + title('Output of each filter'); + subplot(212); + plot(rx_filt_dec(1,st:en),'+'); + hold on; + plot(rx_filt_dec(2,st:en),'g+'); + if M == 4 + plot(rx_filt_dec(3,st:en),'c+'); + plot(rx_filt_dec(4,st:en),'r+'); + end + hold off; + title('Decimated output of each filter'); + end + + figure(3) + clf; + subplot(211) + plot(rx_timing_sig(st*Ts:en*Ts).^2) + title('rx-timing-sig') + subplot(212) + F = abs(fft(rx_timing_sig(1:Fs))); + plot(F(100:8000)) + title('FFT of rx-timing-sig') + + if demod == 1 + figure(4); + clf; + h = fft(rx_out, Fs); + hdB = 20*log10(abs(h)); + plot(hdB(1:4000)) + title('Spectrum of baseband modem signal after analog FM demod'); + axis([1 4000 (max(hdB)-40) max(hdB)]) + end + + if demod == 1 + figure(5) + clf; + subplot(211) + plot(rx_out(st*Ts:en*Ts)); + title('baseband modem signal after analog FM demod'); + subplot(212) + plot(rx_out_hp(st*Ts:en*Ts)); + title('baseband modem signal after 300Hz filter'); + end +end + + +% Run various permutations of simulation here --------------------------------------- + +function run_single + + sim_in.frames = 100; + sim_in.test_frame_mode = 1; + sim_in.M = 2; + sim_in.Rs = 2400; + sim_in.demod = 1; + sim_in.EbNodB = 15; + sim_in.timing_offset = 0.0; + sim_in.hpf = 1; + sim_in.verbose = 1; + + run_sim(sim_in); +endfunction + + +function run_lots + + % adjusted a few scenarios for about 2% BER so we can compare + + sim_in.frames = 100; + sim_in.test_frame_mode = 1; + sim_in.M = 2; + sim_in.Rs = 4800; + sim_in.demod = 1; + sim_in.EbNodB = 12; + sim_in.timing_offset = 0.0; + sim_in.hpf = 1; + sim_in.verbose = 0; + + printf("Rs=4800 2FSK ideal demod\n"); + sim_in.EbNodB = 8.5; sim_in.demod = 2; run_sim(sim_in); + printf("Rs=4800 2FSK analog FM demod, not too shabby and pushes 2400bit/s thru a $40 HT!\n"); + sim_in.EbNodB = 12; sim_in.demod = 1; run_sim(sim_in); + printf("Rs=2400 2FSK analog FM demod, needs more power for same BER! Che?\n"); + sim_in.Rs = 2400; sim_in.EbNodB = 15; run_sim(sim_in); + printf("Hmm, doesnt improve with no 300Hz HPF, maybe due to less deviation?\n"); + sim_in.hpf = 0; run_sim(sim_in); + printf("Rs=2400 4FSK ideal demod, nice low Eb/No!\n"); + sim_in.demod = 2; sim_in.M = 4; sim_in.Rs = 2400; sim_in.EbNodB = 6; run_sim(sim_in); +endfunction + +%run_single; +run_lots; diff --git a/codec2/branches/0.7/octave/melstats.m b/codec2/branches/0.7/octave/melstats.m new file mode 100644 index 00000000..d3735597 --- /dev/null +++ b/codec2/branches/0.7/octave/melstats.m @@ -0,0 +1,49 @@ +% melstats.m +% David Rowe April 2015 +% +% plots some stats of mel/lsp quantisers + +function melstats(filename) + + mel = load(filename); + [m n] = size(mel); + nbins = 10; + + % histograms of each value + + figure(1) + clf + subplot(211) + [h x] = hist(mel(:,1),nbins); + plot(x,h,"1"); + hold on + + for i=2:n + [h x] = hist(mel(:,i),nbins); + colour = sprintf("%d",i); + plot(x,h,colour); + end + hold off + + % histograms differences + + subplot(212) + [h x] = hist(mel(:,1),nbins); + plot(x,h,"1"); + hold on + + for i=2:n + [h x] = hist(mel(:,i)-mel(:,i-1),nbins); + colour = sprintf("%d",i); + plot(x,h, colour); + end + hold off + + figure(2) + plot(mel(:,1),mel(:,2),'r+') + hold on; + plot(mel(:,3),mel(:,4),'g+') + plot(mel(:,5),mel(:,6),'b+') + hold off; + +endfunction diff --git a/codec2/branches/0.7/octave/melvq.m b/codec2/branches/0.7/octave/melvq.m new file mode 100644 index 00000000..ca915036 --- /dev/null +++ b/codec2/branches/0.7/octave/melvq.m @@ -0,0 +1,168 @@ +% melvq.m +% David Rowe Aug 2015 +% +% Experimenting with VQ design for mel LSPs + +% todo: +% [ ] Sorting inside search what happens if we get a order issue, fix and calc SD +% [ ] Search to avoid a worst case error rather than average? This could be included +% in training. +% [ ] nested/staged search + +1; + +% train up multi-stage VQ +% ~/codec2-dev/build_linux/src$ sox -r 8000 -s -2 ../../wav/all.wav -t raw -r 8000 -s -2 - sinc 300 sinc -2600 | ./c2sim - --lpc 6 --lpcpf --lspmel --dump all -o - | play -t raw -r 8000 -s -2 - vol 3 +% +% octave:> load ../build_linux/src/all_mel.txt +% octave:> melvq; vq = trainvq(all_mel, 64, 3); +% octave:> save vq + +function vq = trainvq(training_data, Nvec, stages) + + vq = []; + for i=1:stages + [idx centers] = kmeans(training_data, Nvec); + quant_error = centers(idx,:) - training_data; + printf("mse stage %d: %f\n", i, mean(std(quant_error))); + training_data = quant_error; + vq(:,:,i) = centers; + end + +end + + +function [mse_list index_list] = search_vq(vq, target, m) + + [Nvec order] = size(vq); + + mse = zeros(1, Nvec); + + % find mse for each vector + + for i=1:Nvec + mse(i) = sum((target - vq(i,:)) .^2); + end + + % sort and keep top m matches + + [mse_list index_list ] = sort(mse); + + mse_list = mse_list(1:m); + index_list = index_list(1:m); + +endfunction + + +% Search multi-stage VQ, retaining m best candidates at each stage + +function [res output_vecs ind] = mbest(vqset, input_vecs, m) + + [Nvec order stages] = size(vqset); + [Ninput tmp] = size(input_vecs); + + res = []; % residual error after VQ + output_vecs = []; % quantised ouput vectors + ind = []; % index of vqs + + for i=1:Ninput + + % first stage, find mbest candidates + + [mse_list index_list] = search_vq(vqset(:,:,1), input_vecs(i,:), m); + cand_list = [mse_list' index_list']; + cand_list = sortrows(cand_list,1); + + % subsequent stages ........... + + for s=2:stages + + % compute m targets for next stage, and update path + + prev_indexes = zeros(m,s-1); + for t=1:m + target(t,:) = input_vecs(i,:); + for v=1:s-1 + target(t,:) -= vqset(cand_list(t,v+1),:,v); + end + prev_indexes(t,:) = cand_list(t,2:s); + end + + % search stage s using m targets from stage s-1 + % with m targets, we do m searches which return the m best possibilities + % so we get a matrix with one row per candidate, m*m rows total + % prev_indexes provides us with the path through the VQs for each candidate row + + avq = vqset(:,:,s); + cand_list = []; + for t=1:m + [mse_list index_list] = search_vq(avq, target(t,:), m); + x = ones(m,1)*prev_indexes(t,:); + cand_row = [mse_list' x index_list']; + cand_list = [cand_list; cand_row]; + end + + % sort into m best rows + + cand_list = sortrows(cand_list,1); + cand_list = cand_list(1:m,:); + + end + + % final residual + target(1,:) = input_vecs(i,:); + out = zeros(1,order); + for v=1:stages + target(1,:) -= vqset(cand_list(1,v+1),:,v); + out += vqset(cand_list(1,v+1),:,v); + end + res = [res; target(1,:)]; + output_vecs = [output_vecs; out]; + ind = [ind; cand_list(1,2:1+stages)]; + end + +endfunction + + +% Quantises a set of mel-lsps and saves back to disk so they can be read in by c2sim +% assumes we have a vq saved to disk called vq +% +% ~/codec2-dev/build_linux/src$ sox -r 8000 -s -2 ../../wav/vk5qi.wav -t raw -r 8000 -s -2 - sinc 300 sinc -2600 | ./c2sim - --lpc 6 --lpcpf --lspmel --dump vk5qi -o - | play -t raw -r 8000 -s -2 - vol 3 +% +% octave:> test_run("vk5qi") +% +% ~/codec2-dev/build_linux/src$ sox -r 8000 -s -2 ../../wav/vk5qi.wav -t raw -r 8000 -s -2 - sinc 300 sinc -2600 | ./c2sim - --lpc 6 --lpcpf --phase0 --dec 4 --postfilter --lspmel --lspmelread ../../octave/vk5qi_mel_.out -o - | play -t raw -r 8000 -s -2 - vol 3 + +function ind = test_run(samplename) + + more off; + input_vecs_name = sprintf("../build_linux/src/%s_mel.txt", samplename); + input_vecs_name + mel = load(input_vecs_name); + load vq; + [res mel_ ind] = mbest(vq, mel, 5); + mean(std(res)) + + output_vecs_name = sprintf("%s_mel_.out", samplename); + fmel_ = fopen(output_vecs_name,"wb"); + [r c] = size(mel_); + for i=1:r + fwrite(fmel_, mel_(i,:), "float32"); + end + fclose(fmel_); +end + +%ind = test_run("hts1a"); + +%load "../build_linux/src/all_mel.txt" +%vq = trainvq(all_mel, 64, 3); +%save vq; + +% [X] save text file of "vq quantised mels" +% [X] load back into c2sim at run time +% [X] train on continuous mels +% [X] sorting/stability +% [X] see how it sounds +% [X] Goal is to get VQ sounding OK, similar to UQ at 20 or 40ms dec, +% [X] sig better than current 700 +% [X] check all indexes used with hist diff --git a/codec2/branches/0.7/octave/mfsk.m b/codec2/branches/0.7/octave/mfsk.m new file mode 100644 index 00000000..0414b5e6 --- /dev/null +++ b/codec2/branches/0.7/octave/mfsk.m @@ -0,0 +1,199 @@ +% mfsk.m +% David Rowe Nov 2015 + +% Simulation to test m=2 and m=4 FSK demod + + +1; + +function sim_out = fsk_ber_test(sim_in) + Fs = 96000; + M = sim_in.M; + Rs = sim_in.Rs; + Ts = Fs/Rs; + verbose = sim_in.verbose; + + nbits = sim_in.nbits; + nsym = sim_in.nbits*2/M; + nsam = nsym*Ts; + EsNodB = sim_in.EbNodB + 10*log10(M/2); + + % printf("M: %d nbits: %d nsym: %d\n", M, nbits, nsym); + + if M == 2 + f(1) = -Rs/2; + f(2) = Rs/2; + end + if M == 4 + f(1) = -3*Rs/2; + f(2) = -Rs/2; + f(3) = Rs/2; + f(4) = 3*Rs/2; + end + + % simulate over a range of Eb/No values + + for ne = 1:length(EsNodB) + Nerrs = Terrs = Tbits = 0; + + aEsNodB = EsNodB(ne); + EsNo = 10^(aEsNodB/10); + variance = Fs/(Rs*EsNo); + + % Modulator ------------------------------- + + tx_bits = round(rand(1, nbits)); + tx = zeros(1,nsam); + tx_phase = 0; + + for i=1:nsym + if M == 2 + tone = tx_bits(i) + 1; + else + tone = (tx_bits(2*(i-1)+1:2*i) * [2 1]') + 1; + end + + tx_phase_vec = tx_phase + (1:Ts)*2*pi*f(tone)/Fs; + tx((i-1)*Ts+1:i*Ts) = exp(j*tx_phase_vec); + tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi; + end + + % Channel --------------------------------- + + % We use complex (single sided) channel simulation, as it's convenient + % for the FM simulation. + + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx + noise; + if verbose > 1 + printf("EbNo: %f Eb: %f var No: %f EbNo (meas): %f\n", + EbNo, var(tx)*Ts/Fs, var(noise)/Fs, (var(tx)*Ts/Fs)/(var(noise)/Fs)); + end + + % Demodulator ----------------------------- + + % non-coherent FSK demod + + rx_bb = rx; + dc = zeros(M,nsam); + for m=1:M + dc(m,:) = rx_bb .* exp(-j*(0:nsam-1)*2*pi*f(m)/Fs); + end + + rx_bits = zeros(1, nsym); + for i=1:nsym + st = (i-1)*Ts+1; + en = st+Ts-1; + for m=1:M + int(m,i) = abs(sum(dc(m,st:en))); + end + if m == 2 + rx_bits(i) = int(1,i) < int(2,i); + else + [max_amp tone] = max([int(1,i) int(2,i) int(3,i) int(4,i)]); + if tone == 1 + rx_bits(2*(i-1)+1:2*i) = [0 0]; + end + if tone == 2 + rx_bits(2*(i-1)+1:2*i) = [0 1]; + end + if tone == 3 + rx_bits(2*(i-1)+1:2*i) = [1 0]; + end + if tone == 4 + rx_bits(2*(i-1)+1:2*i) = [1 1]; + end + end + end + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(error_positions); + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose > 1 + figure(2) + clf + Rx = 10*log10(abs(fft(rx))); + plot(Rx(1:Fs/2)); + axis([1 Fs/2 0 50]); + + figure(3) + clf; + subplot(211) + plot(real(rx_bb(1:Ts*20))) + subplot(212) + Rx_bb = 10*log10(abs(fft(rx_bb))); + plot(Rx_bb(1:3000)); + axis([1 3000 0 50]); + + figure(4); + subplot(211) + stem(abs(mark_int(1:100))); + subplot(212) + stem(abs(space_int(1:100))); + end + + if verbose + printf("EbNo (db): %3.2f Terrs: %d BER: %4.3f \n", aEsNodB - 10*log10(M/2), Terrs, Terrs/Tbits); + end + end + + sim_out.TERvec = TERvec; + sim_out.BERvec = BERvec; +endfunction + + +function run_fsk_curves + sim_in.M = 2; + sim_in.Rs = 1200; + sim_in.nbits = 12000; + sim_in.EbNodB = 0:2:20; + sim_in.verbose = 1; + + EbNo = 10 .^ (sim_in.EbNodB/10); + fsk_theory.BERvec = 0.5*exp(-EbNo/2); % non-coherent BFSK demod + fsk2_sim = fsk_ber_test(sim_in); + + sim_in.M = 4; + fsk4_sim = fsk_ber_test(sim_in); + + % BER v Eb/No curves + + figure(1); + clf; + semilogy(sim_in.EbNodB, fsk_theory.BERvec,'r;2FSK theory;') + hold on; + semilogy(sim_in.EbNodB, fsk2_sim.BERvec,'g;2FSK sim;') + semilogy(sim_in.EbNodB, fsk4_sim.BERvec,'b;4FSK sim;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + +end + + +function run_fsk_single + sim_in.M = 4; + sim_in.Rs = 1200; + sim_in.nbits = 5000; + sim_in.EbNodB = 8; + sim_in.verbose = 1; + + fsk_sim = fsk_ber_test(sim_in); +endfunction + + +rand('state',1); +randn('state',1); +graphics_toolkit ("gnuplot"); + +run_fsk_curves +%run_fsk_single + diff --git a/codec2/branches/0.7/octave/newamp.m b/codec2/branches/0.7/octave/newamp.m new file mode 100644 index 00000000..805282b8 --- /dev/null +++ b/codec2/branches/0.7/octave/newamp.m @@ -0,0 +1,1691 @@ +% newamp.m +% +% Copyright David Rowe 2015 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Library of Octave functions to explore new ideas in amplitude +% (spectral envelope) modelling. See newamp_fby (frame by frame +% analysis) and newamp_batch (batch processing for listening tests) +% +% Code here to support a bunch of experimental ideas, many that didn't work out. + +1; +melvq; % mbest VQ functions + +% -------------------------------------------------------------------------------- +% Functions used by rate K mel work +% -------------------------------------------------------------------------------- + +% General 2nd order parabolic interpolator. Used splines orginally, +% but this is much simpler and we don't need much accuracy. Given two +% vectors of points xp and yp, find interpolated values y at points x +% + +% If a point in x is less than the smallest point in xp, we linearly +% interpolate down to (0,0). If a point in x is greater than the +% greatest value in xp, we linearly interpolate down to (xp_max, 0) + +function y = interp_para(xp, yp, xp_max, x) + assert( (length(xp) >=3) && (length(yp) >= 3) ); + + y = zeros(1,length(x)); + k = 1; + for i=1:length(x) + xi = x(i); + + % k is index into xp of where we start 3 points used to form parabola + + while (xp(k) < xi) && (k < length(xp)) + k++; + end + + %printf("xi: %f k = %d\n", xi, k); + if k == 1 + % linear interpolation at low end + x1 = 0; y1 = 0; + x2 = xp(k); y2 = yp(k); + b = (y2-y1)/(x2-x1); + y(i) = b*(xi-x2) + y2; + %printf("lin1 k: %d i: %d xi: %f x1: %f y1: %f\n", k, i, xi, x1, y1); + elseif k < length(xp) + % parabolic interpolation + x1 = xp(k-1); y1 = yp(k-1); + x2 = xp(k); y2 = yp(k); + x3 = xp(k+1); y3 = yp(k+1); + a = ((y3-y2)/(x3-x2)-(y2-y1)/(x2-x1))/(x3-x1); + b = ((y3-y2)/(x3-x2)*(x2-x1)+(y2-y1)/(x2-x1)*(x3-x2))/(x3-x1); + y(i) = a*(xi-x2)^2 + b*(xi-x2) + y2; + %printf("para1 k: %d i: %d xi: %f x1: %f y1: %f\n", k, i, xi, x1, y1); + elseif (k == length(xp)) && (xi < xp(k)) + % parabolic interpolation, but shift xp points back by 1 + x1 = xp(k-2); y1 = yp(k-2); + x2 = xp(k-1); y2 = yp(k-1); + x3 = xp(k); y3 = yp(k); + a = ((y3-y2)/(x3-x2)-(y2-y1)/(x2-x1))/(x3-x1); + b = ((y3-y2)/(x3-x2)*(x2-x1)+(y2-y1)/(x2-x1)*(x3-x2))/(x3-x1); + y(i) = a*(xi-x2)^2 + b*(xi-x2) + y2; + %printf("para2 k: %d i: %d xi: %f x1: %f y1: %f\n", k, i, xi, x1, y1); + elseif k == length(xp) + % linear interpolation at high end + x1 = xp(k); y1 = yp(k); + x2 = xp_max; y2 = 0; + b = (y2-y1)/(x2-x1); + y(i) = b*(xi-x1) + y1; + %printf("lin2 k: %d i: %d xi: %f x1: %f y1: %f\n", k, i, xi, x1, y1); + end + + end +endfunction + + +% choose largest sample in band, idea is we care more about finding +% peaks, can handle some error in frequency. x are non linear +% (arbitrary) sampling points in kHz + +function y = interp_largest(f0_Hz, AmdB, x_kHz) + L = length(AmdB); + x = x_kHz*1000; + y = zeros(1,length(x)); + bw = x(2) - x(1); + k = 1; + + for i=1:length(x) + + % determine limits of this band + + if i>1 + bw = x(i) - x(i-1); + end + band_low = x(i) - bw/2; band_high = x(i) + bw/2; + + % map band limits to harmonics + + if x(i) < f0_Hz + m_low = m_high = 1; + else + m_low = round(band_low/f0_Hz); m_high = round(band_high/f0_Hz)-1; + m_low = max(1, m_low); m_high = min(L, m_high); m_high = max(m_low, m_high); + end + + printf("L: %d f0: %f i: %d band_low: %f band_high: %f m_low: %d m_high: %d\n",L, f0_Hz, i, band_low, band_high, m_low, m_high); + % find max in band + + y(i) = max(AmdB(m_low:m_high)); + end + +endfunction + +% simple linear interpolator + +function y = interp_linear(xp, yp, x) + assert( (length(xp) == 2) && (length(yp) == 2) ); + + m = (yp(2) - yp(1))/(xp(2) - xp(1)); + c = yp(1) - m*xp(1); + + y = zeros(1,length(x)); + for i=1:length(x) + y(i) = m*x(i) + c; + end +endfunction + + +% quantise input sample to nearest value in table, optionally return binary code + +function [quant_out best_i bits] = quantise(levels, quant_in) + + % find closest quantiser level + + best_se = 1E32; + for i=1:length(levels) + se = (levels(i) - quant_in)^2; + if se < best_se + quant_out = levels(i); + best_se = se; + best_i = i; + end + end + + % convert index to binary bits + + numbits = ceil(log2(length(levels))); + bits = zeros(1, numbits); + for b=1:numbits + bits(b) = bitand(best_i-1,2^(numbits-b)) != 0; + end + +endfunction + + +% Quantisation functions for Wo in log freq domain + +function index = encode_log_Wo(Wo, bits) + Wo_levels = 2.^bits; + Wo_min = 2*pi/160; + Wo_max = 2*pi/20; + + norm = (log10(Wo) - log10(Wo_min))/(log10(Wo_max) - log10(Wo_min)); + index = floor(Wo_levels * norm + 0.5); + index = max(index, 0); + index = min(index, Wo_levels-1); +endfunction + + +function Wo = decode_log_Wo(index, bits) + Wo_levels = 2.^bits; + Wo_min = 2*pi/160; + Wo_max = 2*pi/20; + + step = (log10(Wo_max) - log10(Wo_min))/Wo_levels; + Wo = log10(Wo_min) + step*index; + + Wo = 10 .^ Wo; +endfunction + + +% convert index to binary bits + +function bits = index_to_bits(value, numbits) + levels = 2.^numbits; + bits = zeros(1, numbits); + for b=1:numbits + bits(b) = bitand(value,2^(numbits-b)) != 0; + end +end + + +function value = bits_to_index(bits, numbits) + value = 2.^(numbits-1:-1:0) * bits; +endfunction + + +% generate a zig-zag linear to square mapping matrix + +function map = create_zigzag_map(nr,nc) + map = zeros(nr, nc); + + state = 'zig'; + r = c = 1; + + for i=1:nr*nc + + printf("%s r: %d c: %d i %d\n", state, r, c, i); + map(r,c) = i; + + next_state = state; + if state == 'zig' + % move SE + c -= 1; r += 1; + if r > nr + r = nr; c+=2; + next_state = 'zag'; + end + if c < 1 + c = 1; + next_state = 'zag'; + end + end + + if state == 'zag' + % move SE + r -= 1; c +=1; + if c > nc + c = nc; r+=2; + next_state = 'zig'; + end + if r < 1 + r = 1; + next_state = 'zig'; + end + end + state = next_state; + end +endfunction + + +% reshape matrix m as a vector v by reading out elements in zig-zag pattern + +function v = mtov_zigzag(m) + [nr nc] = size(m); + map = zigzag(nr,nc) + v = zeros(1,nr*nc); + for r=1:nr + for c=1:nc + v(map(r,c)) = m(r,c); + end + end +endfunction + + +% extracts DCT information for rate K surface + +function unwrapped_dcts = dct_blocks(surf, Nt=16) + [frames K] = size(surf); + + % break into 160ms blocks, 2D DCT, truncate, IDCT + + Nblocks = floor(frames/Nt); + unwrapped_dcts = zeros(Nblocks,Nt*K); + + for n=1:Nblocks + st = (n-1)*Nt+1; en = st + Nt - 1; + D = dct2(surf(st:en,:)); + unwrapped_dcts(n,:) = reshape(D',1,Nt*K); + end +endfunction + + +% Determines a map for quantising 2D DCT coeffs in order of rms value +% (ie std dev) of each coeff. Those coeffs with the greatest change +% need the most bits to quantise + +function [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(rate_K_surface, nr, nc) + unwrapped_dcts = dct_blocks(rate_K_surface, nr); + [mx mx_ind] = sort(std(unwrapped_dcts)); + mx_ind = fliplr(mx_ind); mx = fliplr(mx); + map = rms_map = zeros(nr,nc); + for i=1:nr*nc + r = floor((mx_ind(i)-1)/nc) + 1; + c = mx_ind(i) - (r-1)*nc; + %printf("%d %d %d\n", i, r, c); + map(r,c) = i; + rms_map(r,c) = mx(i); + end +endfunction + + +% plot histogram of each 2D DCT coeff, so we can get a feel for +% quantiser design + +function plot_dct2_hists(rate_K_surface, nr, nc) + [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(rate_K_surface, nr, nc); + Ncoeff = nr*nc; + fign = 1; subplotn = 1; + close all; figure(fign); clf; + Nplot = 60; + for i=1:Nplot + subplot(5,4,subplotn); + d = unwrapped_dcts(:,mx_ind(i)); + d = round(d/4); + hist(d); + subplotn++; + if (subplotn > 20) && (i != Nplot) + subplotn = 1; + fign++; + figure(fign); clf; + end + end +endfunction + + +% Gather run length data for each 2D DCT coeff, to see if run length encoding +% can help + +function [run_length d]= plot_run_length(rate_K_surface, nr, nc) + [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(rate_K_surface, nr, nc); + Ncoeff = nr*nc; + [Nblocks tmp] = size(unwrapped_dcts); + + % first get histogram of DCT values ----------------------------------- + + % some mild quantisation + + unwrapped_dcts = round(unwrapped_dcts/4); + + % note we only consider first half of DCT coeffs, unlikely to use all + + d = []; + for i=1:Nblocks + d = [d unwrapped_dcts(i,mx_ind(1:Ncoeff/2))]; + end + + % note we remove outliers from plot as very low prob symbols + + d = d(find(abs(d)<10)); + figure(1); clf; [Wi, ii] = hist(d,-10:10,1); plot(ii,Wi); + length(d) + Wi = Wi(find(Wi > 0)); + %sum(Wi) + %-log2(Wi) + %-Wi .* log2(Wi) + printf("bits/symbol: %2.2f\n", sum(-Wi .* log2(Wi))); + + % now measure run lengths -------------------------------------------- + + run_length = zeros(21,Ncoeff); + state = 'idle'; + + for i=2:length(d) + + next_state = state; + + if state == 'idle' + if d(i-1) == d(i) + next_state = 'trac'; + arun_length = 2; + else + run_length(d(i)+10, 1)++; + end + end + + if state == 'trac' + if d(i-1) == d(i) + arun_length++; + else + next_state = 'idle'; + run_length(d(i-1)+10, arun_length)++; + end + end + + state = next_state; + + end + + figure(2); clf; mesh(run_length(:,1:10)); +endfunction + + +% Design kmeans quantisers for each DCT coeff. This didn't work very well. + +function [quantisers nbits] = design_quantisters_kmeans(rate_K_surface, nr, nc, nbits_max) + [map rms_map mx unwrapped_dcts] = create_map_rms(rate_K_surface, nr, nc); + nq = nr*nc; + quantisers = zeros(nq, 2^nbits_max); nbits = zeros(nq,1); + for i=1:nq + + % work out number of levels for this quantiser such that it is a + % power of 2 for integer number of bits + + nlevels = (2^nbits_max); + nbits(i) = round(log2(nlevels)); + nlevels = 2 .^ nbits(i); + + if i <= 100 + printf("%d %d\n", i, nlevels); + [idx, centers] = kmeans(unwrapped_dcts(:,i), nlevels); + quantisers(i,1:nlevels) = sort(centers); + end + end +endfunction + + +% Uniform quantisers designed to fit limits of each DCT coeff + +function [quantisers nlevels] = design_quantisters_uniform(rate_K_surface, nr, nc, nlevels_max) + [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(rate_K_surface, nr, nc); + + nq = nr*nc; + quantisers = zeros(nq, nlevels_max); nlevels = zeros(nq, 1); + + for i=1:nq + d = unwrapped_dcts(:,mx_ind(i)); + d = floor(d/16); + q_min = floor(min(d)); + q_max = ceil(max(d)); + nlevels(i) = q_max-q_min+1; + quantisers(i,1:nlevels(i)) = 16*(q_min:q_max); + end +endfunction + + +% Determine a phase spectra from a magnitude spectra +% from http://www.dsprelated.com/showcode/20.php +% Haven't _quite_ figured out how this works but have to start somewhere .... +% +% TODO: we may be able to sample at a lower rate, like mWo +% but start with something that works +function [phase Gdbfk s Aw] = determine_phase(model, f, Nfft=512, ak) + Fs = 8000; + max_amp = 80; + L = min([model(f,2) max_amp-1]); + Wo = model(f,1); + + sample_freqs_kHz = (Fs/1000)*[0:Nfft/2]/Nfft; % fft frequency grid (nonneg freqs) + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + rate_L_sample_freqs_kHz = (1:L)*Wo*4/pi; + Gdbfk = interp_para(rate_L_sample_freqs_kHz, AmdB, Fs/(2*1000), sample_freqs_kHz); + + % Gdbfk = resample_mask(model, f, mask_sample_freqs_kHz); + + % optional input of aks for testing + + if nargin == 4 + Aw = 1 ./ fft(ak,Nfft); + Gdbfk = 20*log10(abs(Aw(1:Nfft/2+1))); + end + + [phase s] = mag_to_phase(Gdbfk, Nfft); + +endfunction + + +% Non linear sampling of frequency axis, reducing the "rate" is a +% first step before VQ + +function mel = ftomel(fHz) + mel = floor(2595*log10(1+fHz/700)+0.5); +endfunction + + +function rate_K_sample_freqs_kHz = mel_sample_freqs_kHz(K, fstart_hz=100, fend_hz=0.95*4000) + mel_start = ftomel(fstart_hz); mel_end = ftomel(fend_hz); + step = (mel_end-mel_start)/(K-1); + mel = mel_start:step:mel_end; + rate_K_sample_freqs_Hz = 700*((10 .^ (mel/2595)) - 1); + rate_K_sample_freqs_kHz = rate_K_sample_freqs_Hz/1000; +endfunction + + +function plot_mel_sample_freqs(K, f_start_hz, f_end_hz) + rate_K_sample_freqs_kHz = mel_sample_freqs_kHz(K, f_start_hz, f_end_hz); + figure(1); clf; + plot(rate_K_sample_freqs_kHz,'+'); +endfunction + +function [rate_K_surface rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model, K, Fs=8000) + rate_K_sample_freqs_kHz = mel_sample_freqs_kHz(K, 100, 0.95*Fs/2); + rate_K_surface = resample_const_rate_f(model, rate_K_sample_freqs_kHz, Fs); +endfunction + + +% Resample Am from time-varying rate L=floor(pi/Wo) to fixed rate K. This can be viewed +% as a 3D surface with time, freq, and ampitude axis. + +function [rate_K_surface rate_K_sample_freqs_kHz] = resample_const_rate_f(model, rate_K_sample_freqs_kHz, Fs) + + % convert rate L=pi/Wo amplitude samples to fixed rate K + + max_amp = 160; + [frames col] = size(model); + K = length(rate_K_sample_freqs_kHz); + rate_K_surface = zeros(frames, K); + + for f=1:frames + Wo = model(f,1); + L = min([model(f,2) max_amp-1]); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + + clip_en = 0; + if clip_en + % clip between peak and peak -50dB, to reduce dynamic range + + AmdB_peak = max(AmdB); + AmdB(find(AmdB < (AmdB_peak-50))) = AmdB_peak-50; + end + + rate_L_sample_freqs_kHz = (1:L)*Wo*Fs/(2000*pi); + + rate_K_surface(f,:) = interp1([0 rate_L_sample_freqs_kHz (Fs/2000)], [AmdB(1) AmdB AmdB(L)], rate_K_sample_freqs_kHz, "spline"); + %rate_K_surface(f,:) = interp_para(rate_L_sample_freqs_kHz, AmdB, Fs/(2*1000), rate_K_sample_freqs_kHz); + + %printf("%d\n", f); + end + %printf("\n"); +endfunction + + +function [rate_K_vec_corrected orig_error error nasty_error_log nasty_error_m_log] = correct_rate_K_vec(rate_K_vec, rate_K_sample_freqs_kHz, AmdB, AmdB_, K, Wo, L, Fs) + + % aliasing correction -------------------------------------- + + % The mel sample rate decreases as frequency increases. Look for + % any regions above 1000Hz where we have missed definition of a + % spectral peak (formant) due to aliasing. Adjust the rate K + % sample levels to restore peaks. Theory is that correct + % definition of a formant is less important than the frequency of + % the formant. As long as we define a formant in that general + % frequency area it will sound OK. + + Am_freqs_kHz = (1:L)*Wo*4/pi; + + % Lets see where we have made an error + + error = orig_error = AmdB - AmdB_; + + Ncorrections = 3; % maximum number of rate K samples to correct + error_thresh = 3; % only worry about errors larger than thresh + + start_m = floor(L*1000/(Fs/2)); + error(1:start_m) = 0; % first 1000Hz is densly sampled so ignore + nasty_error_m_log = []; nasty_error_log = []; + + + rate_K_vec_corrected = rate_K_vec; + for i=1:Ncorrections + [mx mx_m] = max(error); + + if mx > error_thresh + nasty_error_log = [nasty_error_log mx]; + nasty_error_m_log = [nasty_error_m_log mx_m]; + + % find closest rate K sample to nasty error + + nasty_error_freq = mx_m*Wo*Fs/(2*pi*1000); + [tmp closest_k] = min(abs(rate_K_sample_freqs_kHz - nasty_error_freq)); + rate_K_vec_corrected(closest_k) = AmdB(mx_m); + + % zero out error in this region and look for another large error region + + k = max(1, closest_k-1); + rate_K_prev_sample_kHz = rate_K_sample_freqs_kHz(k); + k = min(K, closest_k+1); + rate_K_next_sample_kHz = rate_K_sample_freqs_kHz(k); + + [tmp st_m] = min(abs(Am_freqs_kHz - rate_K_prev_sample_kHz)); + [tmp en_m] = min(abs(Am_freqs_kHz - rate_K_next_sample_kHz)); + if closest_k == K + en_m = L; + end + error(st_m:en_m) = 0; + end + end +endfunction + + +% Take a rate K surface and convert back to time varying rate L + +function [model_ AmdB_] = resample_rate_L(model, rate_K_surface, rate_K_sample_freqs_kHz, Fs=8000, pad_end=0) + max_amp = 160; K = columns(rate_K_surface); + [frames col] = size(model); + + AmdB_ = zeros(frames, max_amp); + model_ = zeros(frames, max_amp+2); + for f=1:frames + Wo = model(f,1); + L = model(f,2); + rate_L_sample_freqs_kHz = (1:L)*Wo*Fs/(2000*pi); + + % back down to rate L + + % dealing with end effects is an ongoing issue.....need a better solution + + if pad_end + AmdB_(f,1:L) = interp1([0 rate_K_sample_freqs_kHz Fs/2000], + [rate_K_surface(f,1) rate_K_surface(f,:) rate_K_surface(f,K)], + rate_L_sample_freqs_kHz, + "spline"); + else + AmdB_(f,1:L) = interp1([0 rate_K_sample_freqs_kHz], + [rate_K_surface(f,1) rate_K_surface(f,:)], + rate_L_sample_freqs_kHz, + "spline"); + end + + %AmdB_(f,1:L) = interp_para(rate_K_sample_freqs_kHz, rate_K_surface(f,:), Fs/(2*1000), rate_L_sample_freqs_kHz); + %printf("f: %d %f %f %f\n", f, rate_K_sample_freqs_kHz(1), rate_L_sample_freqs_kHz(1), AmdB_(1)); + model_(f,1) = Wo; model_(f,2) = L; model_(f,3:(L+2)) = 10 .^ (AmdB_(f, 1:L)/20); + end +endfunction + + +% PostFilter, has a big impact on speech quality after VQ. When used +% on a mean removed rate K vector, it raises formants, and supresses +% anti-formants. As it manipulates amplitudes, we normalise energy to +% prevent clipping or large level variations. pf_gain of 1.2 to 1.5 +% (dB) seems to work OK. Good area for further investigations and +% improvements in speech quality. + +function vec = post_filter(vec, sample_freq_kHz, pf_gain = 1.5, voicing) + % vec is rate K vector describing spectrum of current frame + % lets pre-emp before applying PF. 20dB/dec over 300Hz + + pre = 20*log10(sample_freq_kHz/0.3); + vec += pre; + + levels_before_linear = 10 .^ (vec/20); + e_before = sum(levels_before_linear .^2); + + vec *= pf_gain; + + levels_after_linear = 10 .^ (vec/20); + e_after = sum(levels_after_linear .^2); + gain = e_after/e_before; + gaindB = 10*log10(gain); + vec -= gaindB; + + vec -= pre; +endfunction + + +% construct energy quantiser table, and save to text file to include in C + +function energy_q = create_energy_q + energy_q = 10 + 40/16*(0:15); +endfunction + +function save_energy_q(fn) + energy_q = create_energy_q; + f = fopen(fn, "wt"); + fprintf(f, "1 %d\n", length(energy_q)); + for n=1:length(energy_q) + fprintf(f, "%f\n", energy_q(n)); + end + fclose(f); +endfunction + + +% save's VQ in format that can be compiled by Codec 2 build system + +function save_vq(vqset, filenameprefix) + [Nvec order stages] = size(vqset); + for s=1:stages + fn = sprintf("%s_%d.txt", filenameprefix, s); + f = fopen(fn, "wt"); + fprintf(f, "%d %d\n", order, Nvec); + for n=1:Nvec + for k=1:order + fprintf(f, "% 8.4f ", vqset(n,k,s)); + end + fprintf(f, "\n"); + end + fclose(f); + end +endfunction + + +% Decoder side interpolation of Wo and voicing, to go from 25 Hz +% sample rate used over channel to 100Hz internal sample rate of Codec +% 2. + +function [Wo_ voicing_] = interp_Wo_v(Wo1, Wo2, voicing1, voicing2) + M = 4; + max_amp = 80; + + Wo_ = zeros(1,M); + voicing_ = zeros(1,M); + if !voicing1 && !voicing2 + Wo_(1:M) = 2*pi/100; + end + + if voicing1 && !voicing2 + Wo_(1:M/2) = Wo1; + Wo_(M/2+1:M) = 2*pi/100; + voicing_(1:M/2) = 1; + end + + if !voicing1 && voicing2 + Wo_(1:M/2) = 2*pi/100; + Wo_(M/2+1:M) = Wo2; + voicing_(M/2+1:M) = 1; + end + + if voicing1 && voicing2 + Wo_samples = [Wo1 Wo2]; + Wo_(1:M) = interp_linear([1 M+1], Wo_samples, 1:M); + voicing_(1:M) = 1; + end + + #{ + printf("f: %d f+M/2: %d Wo: %f %f (%f %%) v: %d %d \n", f, f+M/2, model(f,1), model(f+M/2,1), 100*abs(model(f,1) - model(f+M/2,1))/model(f,1), voicing(f), voicing(f+M/2)); + for i=f:f+M/2-1 + printf(" f: %d v: %d v_: %d Wo: %f Wo_: %f\n", i, voicing(i), voicing_(i), model(i,1), model_(i,1)); + end + #} +endfunction + + +function [diff_weighted weights error g min_ind] = search_vq_weighted(target, vq, weight_gain) + [vq_rows vq_cols] = size(vq); + + weight_gain = 0.1; % I like this vairable name as it is funny + + % find mse for each vector + + error = g = zeros(1, vq_rows); + diff = weights = diff_weighted = zeros(vq_rows, vq_cols); + + weights = max(0.1, weight_gain .* (target + 20)); + + for i=1:vq_rows + + % work out gain for best match + + g(i) = sum((target - vq(i,:)).*weights)/vq_cols; + + % Find weighted difference. This allocated more importance + % (error) to samples with higher energy, and stops really low + % level harmonics from having any impact. Note addition in dB + % is multiplication in linear + + diff(i,:) = target - vq(i,:) - g(i); + + diff_weighted(i,:) = diff(i,:) .* weights; + + % abs in dB is MSE in linear + + error(i) = mean(abs(diff_weighted(i,:))); + end + + [mn min_ind] = min(error); + +endfunction + + +% -------------------------------------------------------------------------------- +% Experimental functions used for masking, piecewise models, not part of newamp1 +% -------------------------------------------------------------------------------- + + +function [maskdB_ maskdB_cyclic Dabs dk_ D1_ ind] = decimate_in_freq(maskdB, cyclic=1, k=7, vq) + + % Lets try to come up with a smoothed, cyclic model. Replace + % points from 3500 Hz to 4000Hz with a sequence that joins without + % a step to points at the 0Hz end of the spectrum. This will make + % it more cyclical and make the DFT happier, less high freq + % energy. Yes, happier is an extremely technical term. + + L = length(maskdB); + anchor = floor(7*L/8); + xpts = [ anchor-1 anchor L+1 L+2]; + ypts = [ maskdB(anchor-1) maskdB(anchor) maskdB(1) maskdB(2)]; + mask_pp = splinefit(xpts, ypts, 1); + maskdB_cyclic = [maskdB(1:anchor) ppval(mask_pp, anchor+1:L)]; + + % Now DFT, truncating DFT coeffs to undersample + + if cyclic + D = fft(maskdB_cyclic)/L; + else + D = fft(maskdB)/L; + end + Dabs = abs(D); % this returned for plotting + + % truncate D to rate k, convert to 2k length real vector for quantisation and transmission + + Dk = [0 D(2:k-1) real(D(k)) D(L-k+1:L)]; + dk = real(ifft(Dk)); + D1 = D(1); + + % quantisation + + if nargin == 4 + [res tmp vq_ind] = mbest(vq, dk, 4); + D1_tab = 0:(60/15):60; + assert(length(D1_tab) == 16); + [tmp D1_ind] = quantise(D1_tab, D1); + ind = [vq_ind D1_ind]; + [dk_ D1_] = index_to_params(ind, vq); + %std(dk_ - dk) + else + dk_ = dk; + D1_ = D1; + end + + maskdB_ = params_to_mask(L, k, dk_, D1_); +endfunction + + + +function [dk_ D1_] = index_to_params(ind, vq) + [Nvec order stages] = size(vq); + dk_ = zeros(1,order); + for s=1:stages + dk_ = dk_ + vq(ind(s),:,s); + end + D1_tab = 0:(60/15):60; + D1_ = D1_tab(ind(stages+1)); +endfunction + + +% decoder side + +function maskdB_ = params_to_mask(L, k, dk_, D1_) + + anchor = floor(7*L/8); + + % convert quantised dk back to rate L magnitude spectrum + + Dk_ = fft(dk_); + D_ = zeros(1,L); + D_(1) = D1_; % energy seperately quantised + D_(2:k-1) = Dk_(2:k-1); + D_(L-k+1:L) = Dk_(k+1:2*k); + d_ = L*ifft(D_); % back to spectrum at rate L + maskdB_ = real(d_); + + % Finally fix up last 500Hz, taper down 10dB at 4000Hz + + xpts = [ anchor-1 anchor L]; + ypts = [ maskdB_(anchor-1) maskdB_(anchor) (maskdB_(anchor)-10)]; + mask_pp = splinefit(xpts, ypts, 1); + maskdB_ = [maskdB_(1:anchor) ppval(mask_pp, anchor+1:L)]; +endfunction + + + +% determine cumulative mask, using amplitude of each harmonic. Mask is +% sampled across L points in the linear domain + +function maskdB = determine_mask(masker_amps_dB, masker_freqs_kHz, mask_sample_freqs_kHz, bark_model=1) + + % calculate and plot masking curve + + maskdB = -20*ones(1,length(mask_sample_freqs_kHz)); + for m=1:length(masker_freqs_kHz) + maskdB = max(maskdB, schroeder(masker_freqs_kHz(m), mask_sample_freqs_kHz, bark_model) + masker_amps_dB(m)); + %maskdB = max(maskdB, parabolic_resonator(masker_freqs_kHz(m), mask_sample_freqs_kHz) + masker_amps_dB(m)); + end +end + + +% Sample mask as model for Am + +function [maskdB Am_freqs_kHz] = mask_model(AmdB, Wo, L, bark_model=1) + + Am_freqs_kHz = (1:L)*Wo*4/pi; + maskdB = determine_mask(AmdB, Am_freqs_kHz, Am_freqs_kHz, bark_model); +endfunction + + +% +% Masking functions from http://www.perceptualentropy.com/coder.html#C +% Thanks Jon Boley! +% + +% Calculate the Schroeder masking spectrum for a given frequency and SPL + +function maskdB = schroeder(freq_tone_kHz, mask_sample_freqs_kHz, bark_model=1) + f_kHz = mask_sample_freqs_kHz; + f_Hz = f_kHz*1000; + + % Schroeder Spreading Function + + if bark_model == 0 + dz = bark(freq_tone_kHz*1000)-bark(f_Hz); + end + + if bark_model == 1 + + % Modification by DR: Piecewise linear model that makes bands + % beneath 1.5kHz wider to match the width of F1 and + % "fill in" the spectra better for UV sounds. + + %x1 = 0.5; x2 = 2; + %y1 = 0.5; y2 = 1; + x1 = 0.5; x2 = 3; + y1 = 1; y2 = 3; + + grad = (y2 - y1)/(x2 - x1); + y_int = y1 - grad*x1; + + if freq_tone_kHz <= x1 + y = y1; + end + if (freq_tone_kHz > x1) && (freq_tone_kHz < x2) + y = grad*freq_tone_kHz + y_int; + end + if freq_tone_kHz >= x2 + y = y2; + end + dz = y*(bark(freq_tone_kHz*1000) - bark(f_Hz)); + end + + if bark_model == 2 + + % constant bandwidth model, useful for bg noise and UV + + %dz = bark(freq_tone_kHz*1000) - bark(f_Hz); + dz = 0.2*bark(freq_tone_kHz*1000-f_Hz); + end + + maskdB = 15.81 + 7.5*(dz+0.474) - 17.5*sqrt(1 + (dz+0.474).^2); +endfunction + + +% Converts frequency to bark scale +% Frequency should be specified in Hertz + +function b=bark(f) + b = 13*atan(0.76*f/1000) + 3.5*atan((f/7500).^2); +endfunction + + +% Alternative mask function that has a gentler slope than schroeder. +% Idea is to get sharp formant definition, but also fill in gaps so we +% dont get chunks of spectrum coming and going + +function [maskdB pp] = resonator(freq_tone_kHz, mask_sample_freqs_kHz) + % note all frequencies in kHz + + f1 = 0.1; f2 = 3; + bw1 = 0.1; bw2 = 0.1; + m = (bw2-bw1)/(log10(f2)-log10(f1)); + c = bw1 - m*log10(f1); + + Fs = 8; + slope = -12; % filter falls off by this slope/octave + + maskdB = zeros(1, length(mask_sample_freqs_kHz)); + + % frequency dependant bandwidth + + bw = m*log10(freq_tone_kHz) + c; + printf("freq_tone_kHz: %f bw: %f\n", freq_tone_kHz, bw); + + % Design spline to set shape based on current bandwidth + + x = [-Fs/2 -bw/2 0 +bw/2 +Fs/2]; + delta = slope*log2(Fs/bw); % gain is delta down from -3dB to Fs/2 + y = [-3 + delta, -3, 0, -3, -3 + delta]; + pp = splinefit(x, y, 4); + maskdB = ppval(pp, mask_sample_freqs_kHz - freq_tone_kHz); +endfunction + + +function maskdB = resonator_fast(freq_tone_kHz, mask_sample_freqs_kHz) + + % note all frequencies on kHz + + #{ + max_ind = length(pp_bw); + ind = round(freq_tone_kHz/0.1); + ind = min(ind, max_ind); + ind = max(ind, 1); + #} + %printf("freq_tone_kHz: %f ind: %d\n", freq_tone_kHz, ind); + [maskdB_res1 pp] = resonator(0.5, mask_sample_freqs_kHz); + + maskdB = ppval(pp, mask_sample_freqs_kHz - freq_tone_kHz); + %maskdB = ppval(pp_bw(ind), mask_sample_freqs_kHz - freq_tone_kHz); +endfunction + + +% Alternative mask function that uses parabolas for fast computation + +function maskdB = parabolic_resonator(freq_tone_kHz, mask_sample_freqs_kHz) + + % note all frequencies in kHz + + % bandwidth as a function of log(f) + + f1 = 0.5; f2 = 3; + bw1 = 0.1; bw2 = 0.3; + m = (bw2-bw1)/(log10(f2)-log10(f1)); + c = bw1 - m*log10(f1); + + Fs = 8; + slope = -18; + + % frequency dependant bandwidth + + if freq_tone_kHz < f1 + bw = bw1; + else + bw = m*log10(freq_tone_kHz) + c; + end + %printf("freq_tone_kHz: %f bw: %f\n", freq_tone_kHz, bw); + + % Design parabola to fit bandwidth + + a = -3/((bw/2)^2); + %printf("freq_tone_kHz: %f bw: %f a: %f\n", freq_tone_kHz, bw, a); + + % Design straight line to fit slope + + delta = slope*log2(Fs/bw); % gain is delta down from -3dB to Fs/2 + m1 = 2*delta/Fs; + + maskdB_par = a*((mask_sample_freqs_kHz - freq_tone_kHz).^2); + maskdB_line = m1*abs(mask_sample_freqs_kHz - freq_tone_kHz) - 10; + %indx = find(mask_sample_freqs_kHz < freq_tone_kHz); + %maskdB_line(indx) = -50; + + maskdB = max(maskdB_par, maskdB_line); +endfunction + + +% sampling the mask in one frame using an arbitrary set of samplng frequencies + +function maskdB = resample_mask(model, f, mask_sample_freqs_kHz) + max_amp = 80; + + Wo = model(f,1); + L = min([model(f,2) max_amp-1]); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + masker_freqs_kHz = (1:L)*Wo*4/pi; + maskdB = determine_mask(AmdB, masker_freqs_kHz, mask_sample_freqs_kHz); +endfunction + + +% decimate frame rate of mask, use linear interpolation in the log domain + +function maskdB_ = decimate_frame_rate(model, decimate, f, frames) + max_amp = 80; + + Wo = model(f,1); + L = min([model(f,2) max_amp]); + + % determine frames that bracket the one we need to interp + + left_f = decimate*floor((f-1)/decimate)+1; + right_f = left_f + decimate; + if right_f > frames + right_f = left_f; + end + + % determine fraction of each frame to use + + left_fraction = 1 - mod((f-1),decimate)/decimate; + right_fraction = 1 - left_fraction; + + printf("f: %d left_f: %d right_f: %d left_fraction: %3.2f right_fraction: %3.2f \n", f, left_f, right_f, left_fraction, right_fraction) + + % fit splines to left and right masks + + left_Wo = model(left_f,1); + left_L = min([model(left_f,2) max_amp]); + left_AmdB = 20*log10(model(left_f,3:(left_L+2))); + left_sample_freqs_kHz = (1:left_L)*left_Wo*4/pi; + + right_Wo = model(right_f,1); + right_L = min([model(right_f,2) max_amp]); + right_AmdB = 20*log10(model(right_f,3:(right_L+2))); + right_sample_freqs_kHz = (1:right_L)*right_Wo*4/pi; + + % determine mask for left and right frames, sampling at Wo for this frame + + sample_freqs_kHz = (1:L)*Wo*4/pi; + maskdB_left = interp1(left_sample_freqs_kHz, left_AmdB, sample_freqs_kHz, "extrap"); + maskdB_right = interp1(right_sample_freqs_kHz, right_AmdB, sample_freqs_kHz, "extrap"); + + maskdB_ = left_fraction*maskdB_left + right_fraction*maskdB_right; +endfunction + + +% plot some masking curves, used for working on masking filter changes + +function plot_masking(bark_model=0); + Fs = 8000; + + figure(1) + mask_sample_freqs_kHz = 0.1:0.025:(Fs/1000)/2; + %maskdB_s0 = schroeder(0.5, mask_sample_freqs_kHz, 0); + %plot(mask_sample_freqs_kHz, maskdB_s0,';schroeder 0;'); + maskdB_s1 = schroeder(0.5, mask_sample_freqs_kHz, bark_model); + plot(mask_sample_freqs_kHz, maskdB_s1,'g;schroeder 1;'); + #{ + maskdB_res = parabolic_resonator(0.5, mask_sample_freqs_kHz); + plot(mask_sample_freqs_kHz, maskdB_res,'r;resonator;'); + #} + hold on; + + for f=0.5:0.5:3 + %maskdB_s0 = schroeder(f, mask_sample_freqs_kHz, 0); + %plot(mask_sample_freqs_kHz, maskdB_s0); + maskdB_s1 = schroeder(f, mask_sample_freqs_kHz, bark_model); + plot(mask_sample_freqs_kHz, maskdB_s1,'g'); + #{ + maskdB_res = parabolic_resonator(f, mask_sample_freqs_kHz); + plot(mask_sample_freqs_kHz, maskdB_res,'r;resonator;'); + #} + end + hold off; + + axis([0.1 4 -30 0]) + grid + + #{ + %pp_bw = gen_pp_bw; + figure(2) + clf; + maskdB_res = resonator(0.5, mask_sample_freqs_kHz); + plot(mask_sample_freqs_kHz, maskdB_res); + hold on; + maskdB_res_fast = resonator_fast(0.5, mask_sample_freqs_kHz); + plot(mask_sample_freqs_kHz, maskdB_res_fast, "g"); + maskdB_par = parabolic_resonator(0.5, mask_sample_freqs_kHz); + plot(mask_sample_freqs_kHz, maskdB_par, "r"); + hold off; + axis([0 4 -80 0]); + grid + #} +endfunction + + +% produce a scatter diagram of amplitudes + +function amp_scatter(samname) + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + [frames nc] = size(model); + max_amp = 80; + + Am_out_name = sprintf("%s_am.out", samname); + freqs = []; + ampsdB = []; + + for f=1:frames + + L = min([model(f,2) max_amp-1]); + Wo = model(f,1); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + + maskdB = mask_model(AmdB, Wo, L); + mask_sample_freqs_kHz = (1:L)*Wo*4/pi; + [newmaskdB local_maxima] = make_newmask(maskdB, AmdB, Wo, L, mask_sample_freqs_kHz); + + [nlm tmp] = size(local_maxima); + freqs = [freqs (local_maxima(1:min(4,nlm),2)*Wo*4000/pi)']; + an_ampsdB = local_maxima(1:min(4,nlm),1)'; + ampsdB = [ampsdB an_ampsdB-mean(an_ampsdB)]; + end + + figure(1) + plot(freqs, ampsdB,'+'); + figure(2) + subplot(211) + hist(freqs,20) + subplot(212) + hist(ampsdB,20) +endfunction + + + +% AbyS returns f & a, this function plots values so we can consider quantisation + +function plot_f_a_stats(f,a) + + % freq pdfs + + [fsrt fsrt_ind] = sort(f,2); + fsrt /= 1000; + figure(1) + for i=1:4 + subplot(2,2,i) + hist(fsrt(:,i),50) + printf("%d min: %d max: %d\n", i, min(fsrt(:,i)), max(fsrt(:,i))) + an_axis = axis; + axis([0 4 an_axis(3) an_axis(4)]) + end + + % freq diff pdfs + + figure(2) + for i=1:4 + subplot(2,2,i) + if i == 1 + hist(fsrt(:,i),50) + else + hist(fsrt(:,i) - fsrt(:,i-1),50) + end + an_axis = axis; + axis([0 4 an_axis(3) an_axis(4)]) + end + + % amplitude PDFs + + l = length(a); + for i=1:l + asrt(i,:) = a(i, fsrt_ind(i,:)); + end + + figure(3) + for i=1:4 + subplot(2,2,i) + hist(asrt(:,i) - mean(asrt(:,:),2)) + an_axis = axis; + axis([-40 40 an_axis(3) an_axis(4)]) + end + + % find straight line fit + + for i=1:l + [gradient intercept] = linreg(1000*fsrt(i,:), asrt(i,:), 4); + alinreg(i,:) = gradient*1000*fsrt(i,:) + intercept; + alinregres(i,:) = asrt(i,:) - alinreg(i,:); + m(i) = gradient; c(i) = intercept; + end + + figure(4) + for i=1:4 + subplot(2,2,i) + hist(alinregres(:,i)) + an_axis = axis; + axis([-40 40 an_axis(3) an_axis(4)]) + end + + figure(5) + subplot(211) + m = m(find(m>-0.05)); + m = m(find(m<0.03)); + hist(m,50) + title('gradient'); + subplot(212) + c = c(find(c>0)); + hist(c,50) + title('y-int'); + +endfunction + +function D1_log = decode_from_bit_stream(samname, ber = 0, bit_error_mask = ones(28,1)) + max_amp = 80; + bits_per_param = [6 1 8 8 4 1]; + assert(sum(bits_per_param) == 28); + load vq; + k = 10; + dec_in_time = 1; + train = 0; + decimate = 4; + synth_phase = 1; + + Am_out_name = sprintf("%s_am.out", samname); + Aw_out_name = sprintf("%s_aw.out", samname); + bit_stream_name = strcat(samname,".bit"); + faw = fopen(Aw_out_name,"wb"); + fam = fopen(Am_out_name,"wb"); + faw = fopen(Aw_out_name,"wb"); + + Wo_out_name = sprintf("%s_Wo.out", samname); + fWo = fopen(Wo_out_name,"wb"); + + % read in bit stream and convert to ind_log[] + + ind_log = []; + fbit = fopen(bit_stream_name, "rb"); + bits_per_frame = sum(bits_per_param); + nind = length(bits_per_param); + nerr = 0; nbits = 0; + [frame nread] = fread(fbit, sum(bits_per_param), "uchar"); + while (nread == bits_per_frame) + + % optionally introduce bit errors + + error_bits = rand(sum(bits_per_param), 1) < ber; + error_bits_masked = bitand(error_bits, bit_error_mask); + frame = bitxor(frame, error_bits_masked); + nerr += sum(error_bits_masked); + nbits += sum(bits_per_param); + + % read a frame, convert to indexes + + nbit = 1; + ind = []; + for i=1:nind + field = frame(nbit:nbit+bits_per_param(i)-1); + nbit += bits_per_param(i); + ind = [ind bits_to_index(field, bits_per_param(i))]; + end + ind_log = [ind_log; ind]; + [frame nread] = fread(fbit, sum(bits_per_param), "uchar"); + endwhile + fclose(fbit); + printf("nerr: %d nbits: %d %f\n", nerr, nbits, nerr/nbits); + + % convert ind_log to modem params + + frames = 4*length(ind_log); + model_ = zeros(frames, max_amp+2); + v = zeros(frames,1); + D1_log = []; + + fdec = 1; + for f=1:4:frames + ind_Wo = ind_log(fdec,1); + + Wo = decode_log_Wo(ind_Wo, 6); + L = floor(pi/Wo); + L = min([L max_amp-1]); + model_(f,1) = Wo; + model_(f,2) = L; + + v1 = ind_log(fdec,2); + if (fdec+1) < length(ind_log) + v5 = ind_log(fdec+1,2); + else + v5 = 0; + end + v(f:f+3) = est_voicing_bits(v1, v5); + + ind_vq = ind_log(fdec,3:5) + 1; + [dk_ D1_] = index_to_params(ind_vq, vq); + D1_log = [D1_log; D1_]; + maskdB_ = params_to_mask(L, k, dk_, D1_); + Am_ = zeros(1,max_amp); + Am_ = 10 .^ (maskdB_(1:L)/20); + model_(f,3:(L+2)) = Am_; + + fdec += 1; + end + + % decoder loop ----------------------------------------------------- + + if train + % short circuit decoder + frames = 0; + end + + % run post filter ahead of time so dec in time has post filtered frames to work with + + for f=1:frames + model_(f,:) = post_filter(model_(f,:)); + end + + for f=1:frames + %printf("frame: %d\n", f); + L = min([model_(f,2) max_amp-1]); + Wo = model_(f,1); + Am_ = model_(f,3:(L+2)); + + maskdB_ = 20*log10(Am_); + + if dec_in_time + % decimate mask samples in time + + [maskdB_ Wo L] = decimate_frame_rate2(model_, decimate, f, frames); + model_(f,1) = Wo; + model_(f,2) = L; + end + + Am_ = zeros(1,max_amp); + Am_(2:L) = 10 .^ (maskdB_(1:L-1)/20); % C array doesnt use A[0] + fwrite(fam, Am_, "float32"); + fwrite(fWo, Wo, "float32"); + + if synth_phase + + % synthesis phase spectra from magnitiude spectra using minimum phase techniques + + fft_enc = 512; + model_(f,3:(L+2)) = 10 .^ (maskdB_(1:L)/20); + phase = determine_phase(model_, f); + assert(length(phase) == fft_enc); + Aw = zeros(1, fft_enc*2); + Aw(1:2:fft_enc*2) = cos(phase); + Aw(2:2:fft_enc*2) = -sin(phase); + fwrite(faw, Aw, "float32"); + end + end + + fclose(fam); + fclose(fWo); + if synth_phase + fclose(faw); + end + + % save voicing file + + v_out_name = sprintf("%s_v.txt", samname); + fv = fopen(v_out_name,"wt"); + for f=1:length(v) + fprintf(fv,"%d\n", v(f)); + end + fclose(fv); + +endfunction + + + +% decimate frame rate of mask, use linear interpolation in the log domain + +function [maskdB_ Wo L] = decimate_frame_rate2(model, decimate, f, frames) + max_amp = 80; + + % determine frames that bracket the one we need to interp + + left_f = decimate*floor((f-1)/decimate)+1; + right_f = left_f + decimate; + if right_f > frames + right_f = left_f; + end + + % determine fraction of each frame to use + + left_fraction = 1 - mod((f-1),decimate)/decimate; + right_fraction = 1 - left_fraction; + + % printf("f: %d left_f: %d right_f: %d left_fraction: %3.2f right_fraction: %3.2f \n", f, left_f, right_f, left_fraction, right_fraction) + + % fit splines to left and right masks + + left_Wo = model(left_f,1); + left_L = min([model(left_f,2) max_amp]); + left_AmdB = 20*log10(model(left_f,3:(left_L+2))); + left_mask_sample_freqs_kHz = (1:left_L)*left_Wo*4/pi; + + right_Wo = model(right_f,1); + right_L = min([model(right_f,2) max_amp]); + right_AmdB = 20*log10(model(right_f,3:(right_L+2))); + right_mask_sample_freqs_kHz = (1:right_L)*right_Wo*4/pi; + + % printf(" right_Wo: %f left_Wo: %f right_L: %d left_L %d\n",right_Wo,left_Wo,right_L,left_L); + printf("%f %f\n", left_AmdB(left_L), right_AmdB(right_L)); + + maskdB_left_pp = splinefit(left_mask_sample_freqs_kHz, left_AmdB, left_L); + maskdB_right_pp = splinefit(right_mask_sample_freqs_kHz, right_AmdB, right_L); + + % determine mask for left and right frames, sampling at Wo for this frame + + Wo = left_fraction*left_Wo + right_fraction*right_Wo; + L = floor(pi/Wo); + %Wo = model(f,1); L = model(f,2); + + mask_sample_freqs_kHz = (1:L)*Wo*4/pi; + maskdB_left = ppval(maskdB_left_pp, mask_sample_freqs_kHz); + maskdB_right = ppval(maskdB_right_pp, mask_sample_freqs_kHz); + + maskdB_ = left_fraction*maskdB_left + right_fraction*maskdB_right; +endfunction + +#{ +function amodel = post_filter(amodel) + max_amp = 80; + + % post filter + + L = min([amodel(2) max_amp-1]); + Wo = amodel(1); + Am_ = amodel(3:(L+2)); + AmdB_ = 20*log10(Am_); + AmdB_pf = AmdB_*1.5; + AmdB_pf += max(AmdB_) - max(AmdB_pf); + amodel(3:(L+2)) = 10 .^ (AmdB_pf(1:L)/20); +endfunction +#} + + +% Given a matrix with indexes on each row, convert to a bit stream and +% write to file. We only write every 4th frame due to DIT + +function write_bit_stream_file(fn, ind_log, bits_per_param) + fbit = fopen(fn,"wb"); + decimate = 4; + + % take a row of quantiser indexes, convert to bits, save to file + + [frames nind] = size(ind_log); + for f=1:decimate:frames + frame_of_bits = []; + arow = ind_log(f,:); + for i=1:nind + %printf("i: %d bits_per_param: %d\n", i, bits_per_param(i)); + some_bits = index_to_bits(arow(i), bits_per_param(i)); + frame_of_bits = [frame_of_bits some_bits]; + end + fwrite(fbit, frame_of_bits, "uchar"); + end + fclose(fbit); +endfunction + + + +% determine 4 voicing bits based on 2 decimated voicing bits + +function [v] = est_voicing_bits(v1, v5) + if v1 == v5 + v(1:4) = v1; + else + v(1:2) = v1; + v(3:4) = v5; + end +endfunction + + +function [AmdB_ residual fvec fvec_ amps] = piecewise_model(AmdB, Wo, vq, vq_m) + L = length(AmdB); + l1000 = floor(L/4); + AmdB_ = ones(1,L); + mask_sample_freqs_kHz = (1:L)*Wo*4/pi; + + % fit a resonator to max of first 300 - 1000 Hz + + fmin = 0.150; + lmin = floor(L*fmin/4); + [mx mx_ind] = max(AmdB(lmin+1:l1000)); + amp(1) = mx; + mx_ind += lmin; + AmdB_ = parabolic_resonator(mx_ind*Wo*4/pi, mask_sample_freqs_kHz) + mx; + fr1 = mx_ind*Wo*4/pi; + + % fit a 2nd resonator, must be above 1000Hz + + fmin = 1; + lmin = round(fmin*L/4); + + [mx mx_ind] = max(AmdB(lmin+1:L)); + amp(2) = mx; + mx_ind += lmin; + AmdB_ = max(AmdB_, parabolic_resonator(mx_ind*Wo*4/pi, mask_sample_freqs_kHz) + mx); + fr2 = mx_ind*Wo*4/pi; + + % fit a third resonator, must be +/- 300 Hz after 2nd resonator + + residual = AmdB - AmdB_; + keep_out = [1:lmin]; + lmax = round(L*3500/4000); + keep_out = [1:lmin lmax:L]; + residual(keep_out) = -40; + + fr2 = mx_ind*Wo*4/pi; + fmin = fr2 - 0.300; + fmax = fr2 + 0.300; + lmin = max(1, round(L*fmin/4)); + lmax = min(L, round(L*fmax/4)); + keep_out = [keep_out lmin:lmax]; + + residual = AmdB; + residual(keep_out) = -40; + + if 0 + figure(3); clf; + subplot(211) + plot(mask_sample_freqs_kHz, residual); + end + + [mx mx_ind] = max(residual); + amp(3) = AmdB(mx_ind); + AmdB_ = max(AmdB_, parabolic_resonator(mx_ind*Wo*4/pi, mask_sample_freqs_kHz) + amp(3)); + fr3 = mx_ind*Wo*4/pi; + + % 4th resonator + + fmin = fr3 - 0.300; + fmax = fr3 + 0.300; + + lmin = max(1, round(L*fmin/4)); + lmax = min(L, round(L*fmax/4)); + keep_out = [keep_out lmin:lmax]; + + residual = AmdB - AmdB_; + residual(keep_out) = -40; + + [mx mx_ind] = max(residual); + amp(4) = AmdB(mx_ind); + AmdB_ = max(AmdB_, parabolic_resonator(mx_ind*Wo*4/pi, mask_sample_freqs_kHz) + amp(4)); + fr4 = mx_ind*Wo*4/pi; + + if 0 + subplot(212) + plot(mask_sample_freqs_kHz, residual); + end + + printf("\nfr1: %f fr2: %f fr3: %f fr4: %f\n", fr1, fr2, fr3, fr4); + [fvec fvec_ind] = sort([fr1 fr2 fr3 fr4]); + amps = amp(fvec_ind(1:4)); + + fvec_ = zeros(1, 4); + + #{ + % optional VQ of frequencies + + if nargin == 4 + AmdB_ = ones(1,L); + [mes fvec_ ind] = mbest(vq, fvec, vq_m); + for i=1:4 + an_amp = amp(fvec_ind(i)); + AmdB_ = max(AmdB_, parabolic_resonator(fvec_(i), mask_sample_freqs_kHz) + an_amp); + end + end + #} + + % optional VQ of amplitudes + + if nargin == 4 + AmdB_ = ones(1,L); + %amps_(1) = amps(1); + %[mes tmp ind] = mbest(vq, amps(2:4) - amps_(1), vq_m); + %amps_(2:4) = amps_(1) + tmp; + [mes amps_ ind] = mbest(vq, amps, vq_m); + amps-amps_ + for i=1:4 + AmdB_ = max(AmdB_, parabolic_resonator(fvec(i), mask_sample_freqs_kHz) + amps_(i)); + end + end + + %amps = amps(2:4) - amps(1); +endfunction + + +% find best place for resonator by closed loop min MSE search + +function lmin = abys(AmdB_, AmdB, Wo, L, mask_sample_freqs_kHz) + lstart = round(L/4); + lmin = lstart; + emin = 1E6; + + printf("lstart: %d L: %d\n", lstart, L); + + figure(3); + subplot(211) + plot(mask_sample_freqs_kHz*1000, AmdB,'r+-'); + + e = zeros(1,L); + for l=lstart:L + + % calc mse + + f_l = l*Wo*4/pi; + AmdB_l = max(AmdB_, parabolic_resonator(f_l, mask_sample_freqs_kHz) + AmdB(l)); + hold on; + if l == 23 + plot(mask_sample_freqs_kHz*1000, AmdB_l,'c'); + end + hold off; + e(l) = sum((AmdB_l - AmdB) .^ 2); + %printf("l: %5d f_l: %4.3f e: %4.0f emin: %4.0f lmin: %5d\n", l, f_l, emin, lmin); + printf("l: %5d f_l: %4.3f e: %4.0f emin: %4.0f lmin: %5d\n", l, f_l, e(l), emin, lmin); + if e(l) < emin + emin = e(l); + lmin = l; + end + end + + subplot(212) + plot(mask_sample_freqs_kHz*1000, e) +endfunction + + +function rate_K_surface_no_slope = remove_slope(rate_K_surface) + [frames K] = size(rate_K_surface); + rate_K_surface_no_slope = zeros(frames,K); + for f=1:frames + [gradient intercept] = linreg(1:K, rate_K_surface(f,:), K); + printf("f: %d gradient: %f intercept: %f\n", f, gradient, intercept); + rate_K_surface_no_slope(f,:) = rate_K_surface(f,:) - (intercept + gradient*(1:K)); + end +endfunction diff --git a/codec2/branches/0.7/octave/newamp1_batch.m b/codec2/branches/0.7/octave/newamp1_batch.m new file mode 100644 index 00000000..cc568943 --- /dev/null +++ b/codec2/branches/0.7/octave/newamp1_batch.m @@ -0,0 +1,1384 @@ +% newamp1_batch.m +% +% Copyright David Rowe 2016 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +#{ + + Octave script to batch process model parameters using the new + amplitude model, version 1. Outputs another set of model parameters + that can be fed to c2sim for listening tests. The companion + newamp1_fbf.m script is used to visualise the processing frame by frame + + c2sim -> dump files -> newamp1_batch.m -> output model params -> c2sim -> play + + The newamp1_xxx scripts have evolved to (i) resample {Am} using a + mel frequency axis, (ii) 2 stage VQ the mean removed vector. Seems to work + OK at 700 bit/s, comparable to 1300. + + Usage: + + build codec2 with -DDUMP - see codec2-dev/README, then: + + ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --dump hts1a + $ cd ~/codec2-dev/octave + octave:14> newamp1_batch("../build_linux/src/hts1a") + ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --amread hts1a_am.out -o - | play -t raw -r 8000 -s -2 - + + Or with a little more processing, first dump energy and voicing, the + import Wo, voicing, phase spectra which simulates all the decoder + DSP. We switch on lpc 10 just to dump voicing. + + $ ./c2sim ../../raw/vk5qi.raw --phase0 --postfilter --dump vk5qi --lpc 10 --dump_pitch_e vk5qi_pitche.txt + octave:14> newamp1_batch("../build_linux/src/vk5qi", "../build_linux/src/vk5qi.out"); + $ ./c2sim ../../raw/vk5qi.raw --phase0 --postfilter --amread vk5qi_am.out --hmread vk5qi_hm.out --Woread vk5qi_Wo.out --hand_voicing vk5qi_v.txt -o - | play -q -t raw -r 8000 -s -2 - + +#} + + +% In general, this function processes a bunch of amplitudes, we then +% use c2sim to hear the results. Bunch of different experiments below + +function [surface mean_f] = newamp1_batch(input_prefix, varargin) + newamp; + more off; + + max_amp = 160; + mean_f = []; + + % defaults + + synth_phase = output = 1; + output_prefix = input_prefix; + vq_type = ""; + vq_filename = ""; + vq_search = "mse"; + mode = "const"; + fit_order = 0; + + % parse variable argument list + + if (length (varargin) > 0) + + % check for the "output_prefix" option + + ind = arg_exists(varargin, "output_prefix"); + if ind + output_prefix = varargin{ind+1}; + end + ind = arg_exists(varargin, "mode"); + if ind + mode = varargin{ind+1}; + end + ind = arg_exists(varargin, "vq_search"); + if ind + vq_search = varargin{ind+1}; + end + ind = arg_exists(varargin, "vq"); + if ind + vq_type = varargin{ind}; + vq_filename = varargin{ind+1}; + printf("vq_type: %s vq_filename: %s vq_search: %s\n", vq_type, vq_filename, vq_search); + end + ind = arg_exists(varargin, "vqh"); + if ind + vq_type = varargin{ind}; + vq_filename = varargin{ind+1}; + printf("vq_type: %s vq_filename: %s vq_search: %s\n", vq_type, vq_filename, vq_search); + end + ind = arg_exists(varargin, "vql"); + if ind + vq_type = varargin{ind}; + vq_filename = varargin{ind+1}; + printf("vq_type: %s vq_filename: %s vq_search: %s\n", vq_type, vq_filename, vq_search); + end + ind = arg_exists(varargin, "no_output"); + if ind + output = 0; + synth_phase = 0; + end + end + + printf("output: %d\n", output); + if (output) + printf("output_prefix: %s\n", output_prefix); + end + + model_name = strcat(input_prefix,"_model.txt"); + model = load(model_name); + [frames nc] = size(model); + + voicing_name = strcat(input_prefix,"_pitche.txt"); + voicing = zeros(1,frames); + + if exist(voicing_name, "file") == 2 + pitche = load(voicing_name); + voicing = pitche(:, 3); + end + + % Choose experiment to run test here ----------------------- + + if strcmp(mode, 'dct2') + [model_ surface] = experiment_rate_K_dct2(model, 0, 1, voicing); + end + if strcmp(mode, 'mel') + [model_ surface] = experiment_mel_freq(model, 0, 1, voicing); + end + if strcmp(mode, 'const') + [model_ surface] = experiment_const_freq(model, vq_type, vq_filename, vq_search); + end + if strcmp(mode, 'piecewise') + model_ = experiment_piecewise(model); + end + if strcmp(mode, 'dct') + model_ = experiment_dct(model); + end + + % ---------------------------------------------------- + + if output + Am_out_name = sprintf("%s_am.out", output_prefix); + fam = fopen(Am_out_name,"wb"); + + Wo_out_name = sprintf("%s_Wo.out", output_prefix); + fWo = fopen(Wo_out_name,"wb"); + + if synth_phase + Hm_out_name = sprintf("%s_hm.out", output_prefix); + fhm = fopen(Hm_out_name,"wb"); + end + + for f=1:frames + %printf("%d ", f); + Wo = model_(f,1); L = min([model_(f,2) max_amp-1]); Am = model_(f,3:(L+2)); + if Wo*L > pi + printf("Problem: %d Wo*L > pi\n", f); + end + + Am_ = zeros(1,max_amp); Am_(2:L) = Am(1:L-1); fwrite(fam, Am_, "float32"); + fwrite(fWo, Wo, "float32"); + + if synth_phase + + % synthesis phase spectra from magnitiude spectra using minimum phase techniques + + fft_enc = 256; + phase = determine_phase(model_, f, fft_enc); + assert(length(phase) == fft_enc); + + % sample phase at centre of each harmonic, not 1st entry Hm[1] in octave Hm[0] in C + % is not used + + Hm = zeros(1, 2*max_amp); + for m=1:L + b = round(m*Wo*fft_enc/(2*pi)); + Hm(2*m) = cos(phase(b)); + Hm(2*m+1) = -sin(phase(b)); + end + fwrite(fhm, Hm, "float32"); + end + end + + fclose(fam); + fclose(fWo); + if synth_phase + fclose(fhm); + end + + % save voicing file + + if exist("voicing_", "var") + v_out_name = sprintf("%s_v.txt", output_prefix); + fv = fopen(v_out_name,"wt"); + for f=1:length(voicing_) + fprintf(fv,"%d\n", voicing_(f)); + end + fclose(fv); + end + end + + for f=1:frames + surface(f,:) -= mean(surface(f,:)); + end + + printf("\n") + +endfunction + + +function surface = slope_and_mean_removal(surface) + [frames K] = size(surface); + for f=1:frames + v = surface(f,:); + [m b] = linreg(1:K, v, K); + v -= m*(1:K) + b; + surface(f,:) = v; + end +endfunction + + +function ind = arg_exists(v, str) + ind = 0; + for i=1:length(v) + if strcmp(v{i}, str) + ind = i; + end + end +endfunction + + +% Basic unquantised rate K linear sampling then back to rate L. Used for generating +% training vectors and testing vector quntisers. + +function [model_ rate_K_surface] = experiment_const_freq(model, vq_type, vq_filename, vq_search="mse") + melvq; + [frames nc] = size(model); + Fs = 8000; + fg = 1; + quant_en = 0; + + rate_K_sample_freqs_kHz = [0.1:0.1:4]; + K = length(rate_K_sample_freqs_kHz); + + % optional full band VQ + + if strcmp(vq_type, "vq") + quant_en = 1; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 1; vq_en = vq_cols; + end + + if strcmp(vq_type, "vql") + quant_en = 1; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 1; vq_en = vq_st + vq_cols - 1; + end + + if strcmp(vq_type, "vqh") + quant_en = 1; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 11; vq_en = K; + end + + energy = zeros(1,frames); + for f=1:frames + L = model(f,2); + energy(f) = 10*log10(sum( model(f,3:(L+2)) .^ 2 )); + end + + rate_K_surface = resample_const_rate_f(model, rate_K_sample_freqs_kHz, Fs); + + rate_K_surface_fit = zeros(frames,K); + b = zeros(1,frames); + + for f=1:frames + b(f) = mean(rate_K_surface(f,:)); + rate_K_surface_fit(f,:) = rate_K_surface(f,:) - b(f); + end + + % optional vector quantise + + if quant_en + + rate_K_surface_fit_ = rate_K_surface_fit; + res = zeros(frames, vq_cols); ind = []; + + for f=1:frames + target = rate_K_surface_fit(f, vq_st:vq_en); + + if strcmp(vq_search, "mse") + [idx contrib errors test_ g mg sl] = vq_search_mse(vq, target); + rate_K_surface_fit_(f, vq_st:vq_en) = contrib; + end + + if strcmp(vq_search, "slope") + [idx contrib errors test_ g mg sl] = vq_search_slope(vq, target); + rate_K_surface_fit_(f, vq_st:vq_en) = contrib; + end + + res(f, vq_st:vq_en) = target - contrib; + ind = [ind idx]; + end + + figure(fg++); clf; mesh(res); + sd_per_frame = std(res(:,vq_st:vq_en)'); + figure(fg++); subplot(211); plot(energy); subplot(212); plot(sd_per_frame); + figure(fg++); subplot(211); hist(sd_per_frame); subplot(212); hist(ind,100); + printf("VQ rms SD: %3.2f\n", mean(sd_per_frame)); + else + rate_K_surface_fit_ = rate_K_surface_fit; + end + + for f=1:frames + rate_K_surface_(f,:) = rate_K_surface_fit_(f,:) + b(f); + end + + [model_ AmdB_] = resample_rate_L(model, rate_K_surface_, rate_K_sample_freqs_kHz, Fs); + + % Measure distortion between AmdB and AmdB_, ths includes distortion + % in the rate K <-> L transition. Can optionally plot distorted + % frames + + plot_sd_thresh = 5; + sd = zeros(1,frames); + for f=1:frames + Wo = model(f,1); + L = model(f,2); + AmdB = 20*log10(model(f,3:(L+2))); + sd(f) = std(AmdB(1:L) - AmdB_(f,1:L)); + if (sd(f) > plot_sd_thresh) && (fg < 10) + printf("fg: %d f: %d\n", fg, f); + figure(fg++); clf; plot((1:L)*Wo*4/pi, AmdB(1:L),'b+-'); hold on; plot((1:L)*Wo*4/pi, AmdB_(f,1:L),'r+-'); + plot(rate_K_sample_freqs_kHz, rate_K_surface_(f,:), 'c+-'); hold off; + end + end + printf("rate K resampling SD: %3.2f\n", mean(sd)); + figure(fg++); clf; subplot(211); plot(energy); subplot(212); plot(sd); title('sdL'); + figure(fg++); clf; hist(sd); +endfunction + + +function model_ = experiment_dct(model) + + [frames tmp] = size(model); max_amp = 160; + + for f=1:frames + printf("%d ", f); + Wo = model(f,1); + L = min([model(f,2) max_amp-1]); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + + % fit model + + D = dct(AmdB); + E = zeros(1,L); + E(1:min(20,L)) = D(1:min(20,L)); + AmdB_ = idct(D); + + model_(f,1) = Wo; model_(f,2) = L; model_(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end + +endfunction + + +% ----------------------------------------------------------------------------------------- +% Linear decimator/interpolator that operates at rate K, includes VQ, post filter, and Wo/E +% quantisation. Evolved from abys decimator below. Simulates the entire encoder/decoder. + +function [model_ voicing_ indexes] = experiment_rate_K_dec(model, voicing) + max_amp = 80; + [frames nc] = size(model); + model_ = zeros(frames, max_amp+3); + indexes = zeros(frames,4); + + M = 4; + + % create frames x K surface. TODO make all of this operate frame by + % frame, or at least M/2=4 frames rather than one big chunk + + K = 20; + [surface sample_freqs_kHz] = resample_const_rate_f_mel(model, K); + target_surface = surface; + + figure(1); + mesh(surface); + + % VQ rate K surface. TODO: If we are decimating by M/2=4 we really + % only need to do this every 4th frame. + + melvq; + load train_120_vq; m=5; + + for f=1:frames + mean_f(f) = mean(surface(f,:)); + surface_no_mean(f,:) = surface(f,:) - mean_f(f); + end + figure(2); + mesh(surface_no_mean); + + [res surface_no_mean_ ind] = mbest(train_120_vq, surface_no_mean, m); + indexes(:,1:2) = ind; + + for f=1:frames + surface_no_mean_(f,:) = post_filter(surface_no_mean_(f,:), sample_freqs_kHz, 1.5); + end + figure(3); + mesh(surface_no_mean_); + + surface_ = zeros(frames, K); + energy_q = create_energy_q; + for f=1:frames + [mean_f_ indx] = quantise(energy_q, mean_f(f)); + indexes(f,3) = indx - 1; + %mean_f_ = mean_f(f); + surface_(f,:) = surface_no_mean_(f,:) + mean_f_; + end + + figure(); + mesh(surface_); + + % break into segments of M frames. We have 3 samples in M frame + % segment spaced M/2 apart and interpolate the rest. This evolved + % from AbyS scheme below but could be simplified to simple linear + % interpolation, or using 3 or 4 points but shift of M/2=4 frames. + + interpolated_surface_ = zeros(frames, K); + for f=1:M:frames-M + left_vec = surface_(f,:); + right_vec = surface_(f+M,:); + sample_points = [f f+M]; + resample_points = f:f+M-1; + for k=1:K + interpolated_surface_(resample_points,k) = interp_linear(sample_points, [left_vec(k) right_vec(k)], resample_points); + end + end + + % break into segments for purposes of Wo interpolation + + for f=1:M:frames + % quantise Wo + + % UV/V flag is coded using a zero index for Wo, this means we need to + % adjust Wo index slightly for the lowest Wo V frames + + if voicing(f) + index = encode_log_Wo(model(f,1), 6); + if index == 0 + index = 1; + end + indexes(f,4) = index; + model_(f,1) = decode_log_Wo(indexes(f,4), 6); + else + indexes(f,4) = 0; + model_(f,1) = 2*pi/100; + end + end + + + voicing_ = zeros(1, frames); + for f=1:M:frames-M + + Wo1_ = model_(f,1); + Wo2_ = model_(f+M,1); + + % uncomment to use unquantised values + %Wo1_ = model(f,1); + %Wo2_ = model(f+M,1); + + if !voicing(f) && !voicing(f+M) + model_(f:f+M-1,1) = 2*pi/100; + end + + if voicing(f) && !voicing(f+M) + model_(f:f+M/2-1,1) = Wo1_; + model_(f+M/2:f+M-1,1) = 2*pi/100; + voicing_(f:f+M/2-1) = 1; + end + + if !voicing(f) && voicing(f+M) + model_(f:f+M/2-1,1) = 2*pi/100; + model_(f+M/2:f+M-1,1) = Wo2_; + voicing_(f+M/2:f+M-1) = 1; + end + + if voicing(f) && voicing(f+M) + Wo_samples = [Wo1_ Wo2_]; + model_(f:f+M-1,1) = interp1([f f+M], Wo_samples, f:f+M-1, "linear", 0); + voicing_(f:f+M-1) = 1; + end + + #{ + printf("f: %d f+M/2: %d Wo: %f %f (%f %%) v: %d %d \n", f, f+M/2, model(f,1), model(f+M/2,1), 100*abs(model(f,1) - model(f+M/2,1))/model(f,1), voicing(f), voicing(f+M/2)); + for i=f:f+M/2-1 + printf(" f: %d v: %d v_: %d Wo: %f Wo_: %f\n", i, voicing(i), voicing_(i), model(i,1), model_(i,1)); + end + #} + end + model_(frames-M:frames,1) = pi/100; % set end frames to something sensible + + % enable these to use original (non interpolated) voicing and Wo + %voicing_ = voicing; + %model_(:,1) = model(:,1); + + model_(:,2) = floor(pi ./ model_(:,1)); % calculate L for each interpolated Wo + model_ = resample_rate_L(model_, interpolated_surface_, sample_freqs_kHz); + +endfunction + + +% --------------------------------------------------------------------------------------- +% Stand alone decoder that takes indexes and creates model_, models +% decoder and an important step in proving everything works + +function [model_ voicing_] = model_from_indexes(indexes) + max_amp = 80; K = 20; M = 4; + + [frames nc] = size(indexes); + model = model_ = zeros(frames, max_amp+3); + sample_freqs_kHz = mel_sample_freqs_kHz(K); + energy_q = 10 + 40/16*(0:15); + + melvq; + load train_120_vq; + + % decode vector quantised surface + + surface_no_mean_ = zeros(frames,K); + surface_ = zeros(frames, K); + for f=1:M:frames + surface_no_mean_(f,:) = train_120_vq(indexes(f,1),:,1) + train_120_vq(indexes(f,2),:,2); + surface_no_mean_(f,:) = post_filter(surface_no_mean_(f,:), sample_freqs_kHz, 1.5); + mean_f_ = energy_q(indexes(f,3)+1); + surface_(f,:) = surface_no_mean_(f,:) + mean_f_; + end + + % break into segments of M frames. We have 2 samples spaced M apart + % and interpolate the rest. + + interpolated_surface_ = zeros(frames, K); + for f=1:M:frames-M + left_vec = surface_(f,:); + right_vec = surface_(f+M,:); + sample_points = [f f+M]; + resample_points = f:f+M-1; + for k=1:K + interpolated_surface_(resample_points,k) = interp_linear(sample_points, [left_vec(k) right_vec(k)], resample_points); + end + end + + % recover Wo and voicing + + voicing = zeros(1, frames); + for f=1:M:frames + if indexes(f,4) == 0 + voicing(f) = 0; + model(f,1) = 2*pi/100; + else + voicing(f) = 1; + model(f,1) = decode_log_Wo(indexes(f,4), 6); + end + end + + % break into M segments for purposes of Wo interpolation + + voicing_ = zeros(1, frames); + for f=1:M:frames-M + + Wo1_ = model(f,1); + Wo2_ = model(f+M,1); + + if !voicing(f) && !voicing(f+M) + model_(f:f+M-1,1) = 2*pi/100; + end + + if voicing(f) && !voicing(f+M) + model_(f:f+M/2-1,1) = Wo1_; + model_(f+M/2:f+M-1,1) = 2*pi/100; + voicing_(f:f+M/2-1) = 1; + end + + if !voicing(f) && voicing(f+M) + model_(f:f+M/2-1,1) = 2*pi/100; + model_(f+M/2:f+M-1,1) = Wo2_; + voicing_(f+M/2:f+M-1) = 1; + end + + if voicing(f) && voicing(f+M) + Wo_samples = [Wo1_ Wo2_]; + model_(f:f+M-1,1) = interp_linear([f f+M], Wo_samples, f:f+M-1); + voicing_(f:f+M-1) = 1; + end + + #{ + printf("f: %d f+M/2: %d Wo: %f %f (%f %%) v: %d %d \n", f, f+M/2, model(f,1), model(f+M/2,1), 100*abs(model(f,1) - model(f+M/2,1))/model(f,1), voicing(f), voicing(f+M/2)); + for i=f:f+M/2-1 + printf(" f: %d v: %d v_: %d Wo: %f Wo_: %f\n", i, voicing(i), voicing_(i), model(i,1), model_(i,1)); + end + #} + end + model_(frames-M:frames,1) = pi/100; % set end frames to something sensible + + % enable these to use original (non interpolated) voicing and Wo + %voicing_ = voicing; + %model_(:,1) = model(:,1); + + model_(:,2) = floor(pi ./ model_(:,1)); % calculate L for each interpolated Wo + model_ = resample_rate_L(model_, interpolated_surface_, sample_freqs_kHz); + +endfunction + + +% --------------------------------------------------------------------------------------- +% Stand alone decoder that takes indexes and creates model_, just like +% model_from_indexes above. This version is refactored to perform frame by frame +% processing, as a stepping stone to C. + +function [model_ voicing_] = model_from_indexes_fbf(indexes) + max_amp = 80; K = 20; M = 4; + + [frames nc] = size(indexes); + model = model_ = zeros(frames, max_amp+3); + sample_freqs_kHz = mel_sample_freqs_kHz(K); + energy_q = 10 + 40/16*(0:15); + + melvq; + load train_120_vq; + + surface_no_mean_ = zeros(frames,K); + surface_ = zeros(frames, K); + interpolated_surface_ = zeros(frames, K); + voicing = zeros(1, frames); + voicing_ = zeros(1, frames); + + for f=1:M:frames + % decode vector quantised surface + + surface_no_mean_(f,:) = train_120_vq(indexes(f,1),:,1) + train_120_vq(indexes(f,2),:,2); + surface_no_mean_(f,:) = post_filter(surface_no_mean_(f,:), sample_freqs_kHz, 1.5); + mean_f_ = energy_q(indexes(f,3)+1); + surface_(f,:) = surface_no_mean_(f,:) + mean_f_; + + % break into segments of M frames. We have 2 samples spaced M apart + % and interpolate the rest. + + if f > M + left_vec = surface_(f-M,:); + right_vec = surface_(f,:); + sample_points = [f-M f]; + resample_points = f-M:f-1; + for k=1:K + interpolated_surface_(resample_points,k) = interp_linear(sample_points, [left_vec(k) right_vec(k)], resample_points); + end + end + + % recover Wo and voicing + + if indexes(f,4) == 0 + voicing(f) = 0; + model(f,1) = 2*pi/100; + else + voicing(f) = 1; + model(f,1) = decode_log_Wo(indexes(f,4), 6); + end + + if f > M + Wo1 = model(f-M,1); + Wo2 = model(f,1); + + [Wo_ avoicing_] = interp_Wo_v(Wo1, Wo2, voicing(f-M), voicing(f)); + model_(f-M:f-1,1) = Wo_; + voicing_(f-M:f-1) = avoicing_; + model_(f-M:f-1,2) = floor(pi ./ model_(f-M:f-1,1)); % calculate L for each interpolated Wo + end + + end + + model_(frames-M:frames,1) = pi/100; % set end frames to something sensible + model_(frames-M:frames,2) = floor(pi ./ model_(frames-M:frames,1)); + + model_ = resample_rate_L(model_, interpolated_surface_, sample_freqs_kHz); + +endfunction + + + +% --------------------------------------------------------------------------------------- +% Various experiments tried during development + +% rate K mel-resampling, high end correction, and DCT experiment workhorse + +function [model_ rate_K_surface] = experiment_rate_K_dct2(model, vq_en=0, plots=1, voicing) + [frames nc] = size(model); + K = 20; Fs = 8000; correct_rate_K_en = 1; + + %quantisers = load("dct2quant.txt"); + %nlevels = load("dct2quantnlevels.txt"); + %map = load("dct2map.txt"); + + for f=1:frames + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + Am_freqs_kHz = (1:L)*Wo*4/pi; + [rate_K_vec rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model(f,:), K); + if correct_rate_K_en + [tmp_ AmdB_] = resample_rate_L(model(f,:), rate_K_vec, rate_K_sample_freqs_kHz); + [rate_K_vec_corrected orig_error error nasty_error_log nasty_error_m_log] = correct_rate_K_vec(rate_K_vec, rate_K_sample_freqs_kHz, AmdB, AmdB_, K, Wo, L, Fs); + rate_K_surface(f,:) = rate_K_vec_corrected; + else + rate_K_surface(f,:) = rate_K_vec; + end + end + + % break into 160ms blocks, 2D DCT, truncate, IDCT + + Tf = 0.01; % frame period in seconds + Nt = 16; % number of 10ms frames blocks in time + dec = 2; % decimation factor + dist_dB = 2; % use enough coefficients to get this distortion ond DCT coeffs + + Nblocks = floor(frames/(Nt*dec)); + printf("frames: %d Nblocks: %d\n", frames, Nblocks); + + unwrapped_dcts = zeros(Nblocks,Nt*K); + rate_K_surface_ = zeros(frames, K); + + % create map on the fly from train database + + asurf = load("all_surf.txt"); [nr nc] = size(asurf); + asurf = asurf(1:dec:nr,:); + [map rms_map mx mx_ind unwrapped_dcts] = create_map_rms(asurf, Nt, K); + %map = create_zigzag_map(Nt,K); + + %printf("non zero coeffs: %d\n", sum(sum(map == 1))); + figure(2); clf; + mesh(map); + sumnz = zeros(1,Nblocks); + dct2_sd = zeros(1,Nblocks); + + % create quantiser_num to r,c Luts + + rmap = cmap = zeros(1,Nt*K); + for r=1:Nt + for c=1:K + quantiser_num = map(r,c); + rmap(quantiser_num) = r; + cmap(quantiser_num) = c; + end + end + + for n=1:Nblocks + st = (n-1)*dec*Nt+1; en = st + dec*Nt - 1; + %printf("st: %d en: %d\n", st, en); + D = dct2(rate_K_surface(st:dec:en,:)); + + % move over surface and work out quantiser + % quantise, replace on map + + E = mapped = zeros(Nt,K); + #{ + for r=1:Nt + for c=1:K + quantiser_num = map(r,c); + if quantiser_num <= 40 + %printf("r %d c %d quantiser_num %d nlevels %d ", r, c, quantiser_num, nlevels(quantiser_num)); + %levels = quantisers(quantiser_num, 1:nlevels(quantiser_num)); + %quant_out = quantise(levels, D(r,c)); + E(r,c) = D(r,c); + if E(r,c) + mapped(r,c) = 1; + sumnz(n)++; + end + end + end + end + #} + + qn = 0; + adct2_sd = mean(std(D-E)); + while adct2_sd > dist_dB + qn++; + E(rmap(qn), cmap(qn)) = 1*round(D(rmap(qn), cmap(qn))/1); + adct2_sd = mean(std(D-E)); + %printf("qn %d %f\n", qn, adct2_sd); + end + sumnz(n) = qn; + + % note neat trick to interpolate to 10ms frames despite dec + + #{ + energy = sum(sum(E)); + Edc = E(1,1); + E = E*1.2; + E(1,1) = Edc/1.2; + #} + %E *= energy/sum(sum(E)); + rate_K_surface_(st:en,:) = idct2([sqrt(dec)*E; zeros(Nt*(dec-1), K)]); + + dct2_sd(n) = mean(std(D-E)); + end + + % figure(3); clf; mesh(mapped); + figure(4); clf; plot(sumnz); hold on; plot([1 length(sumnz)],[mean(sumnz) mean(sumnz)]); hold off; title('Non Zero'); + figure(5); clf; plot(dct2_sd); title('DCT SD'); + printf("average dct spectral distortion: %3.2f dB\n", mean(dct2_sd)); + printf("mean number of coeffs/DCT: %3.2f/%d\n", mean(sumnz), Nt*K); + printf("coeffs/second: %3.2f\n", mean(sumnz)/(Nt*Tf*dec)); + printf("bits/s: %3.2f\n", 2.9*mean(sumnz)/(Nt*Tf*dec)); + + % optional 700C style post filter + + post_filter_en = 0; + if post_filter_en + for f=1:Nt*Nblocks + mn = mean(rate_K_surface_(f,:)); + rate_K_surface_no_mean_(f,:) = rate_K_surface_(f,:) - mn; + rate_K_surface_(f,:) = mn + post_filter(rate_K_surface_no_mean_(f,:), rate_K_sample_freqs_kHz); + end + end + + % prevent /0 errors at end of run + + rate_K_surface_(dec*Nt*Nblocks+1:frames,:) = rate_K_surface(dec*Nt*Nblocks+1:frames,:); + model_ = resample_rate_L(model, rate_K_surface_, rate_K_sample_freqs_kHz); + + dist = std((rate_K_surface_(1:dec:frames,:) - rate_K_surface(1:dec:frames,:))'); + figure(1); clf; plot(dist); title('Rate K SD'); + printf("Rate K spectral distortion mean: %3.2f dB var: %3.2f\n", mean(dist), var(dist)); +endfunction + + +% Basic unquantised rate K mel-sampling then back to rate L. Now with "high end correction" + +function [model_ rate_K_surface] = experiment_mel_freq(model, vq_en=0, plots=1, voicing) + [frames nc] = size(model); + K = 20; Fs = 16000; correct_rate_K_en = 0; + + for f=1:frames + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + Am_freqs_kHz = (1:L)*Wo*Fs/(2000*pi); + [rate_K_vec rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model(f,:), K, Fs); + if correct_rate_K_en + [tmp_ AmdB_] = resample_rate_L(model(f,:), rate_K_vec, rate_K_sample_freqs_kHz, Fs); + [rate_K_vec_corrected orig_error error nasty_error_log nasty_error_m_log] = correct_rate_K_vec(rate_K_vec, rate_K_sample_freqs_kHz, AmdB, AmdB_, K, Wo, L, Fs); + rate_K_surface(f,:) = rate_K_vec_corrected; + else + rate_K_surface(f,:) = rate_K_vec; + end + end + + model_ = resample_rate_L(model, rate_K_surface, rate_K_sample_freqs_kHz, Fs); + +endfunction + + + +% mel spaced sampling, differential in time VQ. Curiously, couldn't +% get very good results out of this, I suspect a bug + +function [model_ rate_K_surface_diff] = experiment_mel_diff_freq(model, vq_en=0) + [frames nc] = size(model); + K = 20; + [rate_K_surface rate_K_sample_freqs_kHz] = resample_const_rate_f_mel(model, K); + + if vq_en + melvq; + load surface_diff_vq; m=5; + end + + for f=1:frames + mean_f(f,:) = mean(rate_K_surface(f,:)); + rate_K_surface_no_mean(f,:) = rate_K_surface(f,:) - mean_f(f,:); + end + + rate_K_surface_no_mean_ = zeros(frames, K); + rate_K_surface_no_mean_diff = zeros(frames, K); + rate_K_surface_(1,:) = rate_K_surface_diff(1,:) = zeros(1, K); + + for f=2:frames + rate_K_surface_diff(f,:) = rate_K_surface_no_mean(f,:) - 0.8*rate_K_surface_no_mean_(f-1,:); + if vq_en + [res arate_K_surface_diff_ ind] = mbest(surface_diff_vq, rate_K_surface_diff(f,:), m); + rate_K_surface_diff_(f,:) = arate_K_surface_diff_; + else + rate_K_surface_diff_(f,:) = rate_K_surface_diff(f,:); + end + rate_K_surface_no_mean_(f,:) = 0.8*rate_K_surface_no_mean_(f-1,:) + rate_K_surface_diff_(f,:); + end + + for f=1:frames + rate_K_surface_(f,:) = rate_K_surface_no_mean_(f,:) + mean_f(f,:); + end + + model_ = resample_rate_L(model, rate_K_surface_, rate_K_sample_freqs_kHz); + +endfunction + + +% try vq with open and closed loop mean removal, turns out they give +% identical results lol + +function [model_ rate_K_surface] = experiment_closed_loop_mean(model) + [frames nc] = size(model); + K = 15; + mel_start = ftomel(300); mel_end = ftomel(3000); + step = (mel_end-mel_start)/(K-1); + mel = mel_start:step:mel_end; + rate_K_sample_freqs_Hz = 700*((10 .^ (mel/2595)) - 1); + rate_K_sample_freqs_kHz = rate_K_sample_freqs_Hz/1000; + + rate_K_surface = resample_const_rate_f(model, rate_K_sample_freqs_kHz); + + load surface_vq; m=1; + + for f=1:frames + amean = mean(rate_K_surface(f,:)); + rate_K_target_no_mean = rate_K_surface(f,:) - amean; + mse_open_loop(f) = search_vq2(surface_vq(:,:,1), rate_K_target_no_mean, m, 0); + mse_closed_loop(f) = search_vq2(surface_vq(:,:,1), rate_K_surface(f,:), m, 1); + end + + printf("rms open loop..: %f\nrms closed loop: %f\n", sqrt(mean(mse_open_loop)), sqrt(mean(mse_closed_loop))); + + % just return model_ as we have to so nothing breaks, it's not actually useful + + model_ = resample_rate_L(model, rate_K_surface, rate_K_sample_freqs_kHz); + +endfunction + + +% Experiment with 10ms update rate for energy but 40ms update for spectrum, +% using linear interpolation for spectrum. + +function model_c = experiment_energy_rate_linear(model, vq_en, plot_en) + max_amp = 80; + [frames nc] = size(model); + + % 10ms mel freq modelling and VQ + + model_ = experiment_mel_freq(model, vq_en, plot_en); + + % Remove energy. Hmmmm, this is done on Ams rather than surface but that's + % similar I guess + + e = zeros(1,frames); + model_a = zeros(frames,max_amp+3); + for f=1:frames + L = min([model_(f,2) max_amp-1]); + Am_ = model_(f,3:(L+2)); + AmdB_ = 20*log10(Am_); + mean_f(f) = mean(AmdB_); + AmdB_ -= mean_f(f); + model_a(f,1) = model_(f,1); model_a(f,2) = L; model_a(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end + + % linear interp after removing energy (mean AmdB) + + model_b = experiment_dec_linear(model_a); + + % add back in energy + + model_c = zeros(frames,max_amp+3); + for f=1:frames + L = min([model_b(f,2) max_amp-1]); + Am_ = model_b(f,3:(L+2)); + AmdB_ = 20*log10(Am_); + AmdB_ += mean_f(f); + model_c(f,1) = model_b(f,1); model_c(f,2) = L; model_c(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end + +endfunction + + +% conventional decimation in time without any filtering, then linear +% interpolation. Linear interpolation is a two-tap (weak) form of fir +% filtering that may have problems with signals with high freq +% components, for example after quantisation noise is added. Need to +% look into this some more. + +function model_ = experiment_dec_linear(model) + newamp; + max_amp = 80; + + [frames nc] = size(model); + model_ = zeros(frames, max_amp+3); + decimate = 4; + for f=1:frames + AmdB_ = decimate_frame_rate(model, decimate, f, frames); + L = length(AmdB_); + model_(f,1) = model(f,1); model_(f,2) = L; model_(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end +endfunction + + + +% Experimental AbyS decimator that chooses best frames to match +% surface based on AbyS approach. Can apply post filter at different +% points, and optionally do fixed decimation, at rate K. Didn't +% produce anything spectacular in AbyS mode, suggest another look with +% some sort of fbf display to see what's going on internally. + +function model_ = experiment_dec_abys(model, M=8, vq_en=0, pf_en=1, fixed_dec=0, voicing) + max_amp = 80; + [frames nc] = size(model); + model_ = zeros(frames, max_amp+3); + + printf("M: %d vq_en: %d pf_en: %d fixed_dec: %d\n", M, vq_en, pf_en, fixed_dec) + + % create frames x K surface + + K = 20; + [surface sample_freqs_kHz] = resample_const_rate_f_mel(model, K); + target_surface = surface; + + % optionaly VQ surface + + if vq_en + melvq; + load train_120_vq; m=5; + + for f=1:frames + mean_f(f) = mean(surface(f,:)); + rate_K_surface_no_mean(f,:) = surface(f,:) - mean_f(f); + end + + [res rate_K_surface_ ind] = mbest(train_120_vq, rate_K_surface_no_mean, m); + + if pf_en == 1 + for f=1:frames + rate_K_surface_(f,:) = post_filter(rate_K_surface_(f,:), sample_freqs_kHz, 1.5, voicing(f)); + end + end + + for f=1:frames + rate_K_surface_(f,:) += mean_f(f); + end + + surface = rate_K_surface_; + end + + % break into segments of M frames. Fix end points, that two of the + % frames we sample. Then find best choice in between + + surface_ = zeros(frames, K); + best_surface_ = zeros(frames, K); + + for f=1:M:frames-M + + left_vec = surface(f,:); + right_vec = surface(f+M,:); + resample_points = f:f+M-1; + best_mse = 1E32; + best_m = f+1; + + + if fixed_dec + m = f+M/2; + printf("%d %d %d\n", f, m, M+f); + centre_vec = surface(m,:); + sample_points = [f m f+M]; + for k=1:K + best_surface_(resample_points,k) = interp1(sample_points, [left_vec(k) centre_vec(k) right_vec(k)], resample_points, "spline", 0); + end + else + printf("%d %d\n", f, M+f); + for m=f+1:M+f-2 + + % Use interpolation to construct candidate surface_ segment + % using just threee samples + + centre_vec = surface(m,:); + sample_points = [f m f+M]; + mse = 0; + for k=1:K + surface_(resample_points,k) = interp1(sample_points, [left_vec(k) centre_vec(k) right_vec(k)], resample_points, "spline", 0); + mse += sum((target_surface(resample_points,k) - surface_(resample_points,k)).^2); + end + + % compare synthesised candidate to orginal and chose min ased on MSE + + if mse < best_mse + best_mse = mse; + best_m = m; + best_surface_(resample_points,:) = surface_(resample_points,:); + end + + printf(" m: %d mse: %f best_mse: %f best_m: %d\n", m, mse, best_mse, best_m); + end + end + end + + if pf_en == 2 + + % Optionally apply pf after interpolation, theory is interpolation + % smooths spectrum in time so post filtering afterwards may be + % useful. Note we remove mean, this tends to move formats up and + % anti-formants down when we multiply by a constant + + for f=1:frames + mean_f = mean(best_surface_(f,:)); + rate_K_vec_no_mean = best_surface_(f,:) - mean_f; + rate_K_vec_no_mean *= 1.2; + best_surface_(f,:) = rate_K_vec_no_mean + mean_f; + end + end + + model_ = resample_rate_L(model, best_surface_, sample_freqs_kHz); + figure(5); + plot(mean_f,'+-') + figure(6) + hist(mean_f) +endfunction + + +#{ + Filtering time axis or surface, as a first step before decimation. + So given surface, lets look at spectral content and see if we can + reduce it while maintaining speech quality. First step is to dft + across time and plot. + + This just has one filtering step, which may help quantisation. In practice + we may need filtering before decimation and at the inerpolation stage +#} + +function model_ = experiment_filter(model) + [frames nc] = size(model); + K = 40; rate_K_sample_freqs_kHz = (1:K)*4/K; + [rate_K_surface rate_K_sample_freqs_kHz] = resample_const_rate_f(model, rate_K_sample_freqs_kHz); + + Nf = 4; Nf2 = 6; + [b a]= cheby1(4, 1, 0.20); + %Nf = 20; Nf2 = 10; + %b = fir1(Nf, 0.25); a = [1 zeros(1, Nf)]; + %Nf = 1; Nf2 = 1; + %b = 1; a = [1 zeros(1, Nf)]; + + %Nf = 2; Nf2 = 1; + %beta = 0.99; w = pi/4; + %b = [1 -2*beta*cos(w) beta*beta]; a = [1 zeros(1, Nf)]; + %Nf = 10; Nf2 = 10; + %b = fir2(10, [0 0.2 0.3 1], [1 1 0.1 0.1]); a = [1 zeros(1, Nf)]; + + %Nf = 1; Nf2 = 1; + dft_surface = zeros(frames,K); + rate_K_surface_filt = zeros(frames,K); + dft_surface_filt = zeros(frames,K); + for k=1:K + dft_surface(:,k) = fft(rate_K_surface(:,k).*hanning(frames)); + %rate_K_surface_filt(:,k) = filter(b, a, rate_K_surface(:,k)); + rate_K_surface_filt(:,k) = filter(b, a, rate_K_surface(:,k)); + dft_surface_filt(:,k) = fft(rate_K_surface_filt(:,k).*hanning(frames)); + end + figure(1); clf; + mesh(abs(dft_surface)) + figure(2); clf; + mesh(abs(dft_surface_filt)) + + Fs = 100; Ts = 1/Fs; + figure(3); + subplot(211); + h = freqz(b,a,Fs/2); + plot(1:Fs/2, 20*log10(abs(h))) + axis([1 Fs/2 -40 0]) + ylabel('Gain (dB)') + grid; + subplot(212) + [g w] = grpdelay(b,a); + plot(w*Fs/pi, 1000*g*Ts) + %axis([1 Fs/2 0 0.5]) + xlabel('Frequency (Hz)'); + ylabel('Delay (ms)') + grid + + figure(4); clf; stem(filter(b,a,[1 zeros(1,20)])) + + % adjust for time offset due to filtering + + rate_K_surface_filt = [rate_K_surface_filt(Nf2:frames,:); zeros(Nf2, K)]; + + % back down to rate L + + model_ = resample_rate_L(model, rate_K_surface_filt, rate_K_sample_freqs_kHz); +endfunction + + +% filter, decimate, zero insert, filter, simulates decimation and re-interpolation, as +% an alternative to simple linear interpolation. + +function model_ = experiment_filter_dec_filter(model) + [frames nc] = size(model); + + % rate K surface + + K = 40; rate_K_sample_freqs_kHz = (1:K)*4/K; + [rate_K_surface rate_K_sample_freqs_kHz] = resample_const_rate_f(model, rate_K_sample_freqs_kHz); + + % filter, not we run across each of the K bins, treating them as a 1-D sequence + + Nf = 4; filter_delay = 12; + [b a]= cheby1(4, 1, 0.20); + %Nf = 10; Nf2 = Nf/2; filter_delay = Nf2*2; + %b = fir1(Nf, 0.25); a = [1 zeros(1, Nf)]; + %Nf = 10; Nf2 = 2; filter_delay = 2*Nf2; + %b = fir2(10, [0 0.2 0.3 1], [1 1 0.1 0.1]); a = [1 zeros(1, Nf)]; + + rate_K_surface_filt = zeros(frames,K); + for k=1:K + rate_K_surface_filt(:,k) = filter(b, a, rate_K_surface(:,k)); + end + + % decimate from 100 to 25Hz, and zero pad, which we simulate by + % setting all K samples in 3 out of 4 time-samples to zero + + M = 4; + + for f=1:frames + if mod(f,M) + rate_K_surface_filt(f,:) = zeros(1,K); + end + end + + % filter to reconstruct 100 Hz frame rate + + rate_K_surface_filt_recon = zeros(frames,K); + for k=1:K + rate_K_surface_filt_recon(:,k) = filter(b, a, M*rate_K_surface_filt(:,k)); + end + + figure(1); clf; + mesh(rate_K_surface_filt) + figure(2); clf; + mesh(rate_K_surface_filt_recon) + + % adjust for time offset due to 2 lots of filtering + + rate_K_surface_filt_recon = [rate_K_surface_filt_recon(filter_delay:frames,:); zeros(filter_delay, K)]; + + % back down to rate L + + model_ = resample_rate_L(model, rate_K_surface_filt_recon, rate_K_sample_freqs_kHz); +endfunction + + +% smoothing using masking functions + +function model_ = experiment_smoothed(model, bark_model=1) + [frames nc] = size(model); + + model_ = model; + + for f=1:frames + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + [AmdB_ Am_freqs_kHz] = mask_model(AmdB, Wo, L, bark_model); + model_(f,3:(L+2)) = 10 .^ ((AmdB_)/20); + end + +endfunction + +#{ + + My original idea was to used a 3-4 "resonators" to construct a + piecewise model of the spectrum. Kind of got distracted by the + surface and mel sampling that ended up working OK. This method was + working OK, soem issues with background noise but rather easy to + quantise. + + todo: get this working again +#} + +function model_ = experiment_piecewise(model) + + [frames tmp] = size(model); max_amp = 160; + + fvec_log = []; amps_log = []; + + for f=1:frames + printf("%d ", f); + Wo = model(f,1); + L = min([model(f,2) max_amp-1]); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + e(f) = sum(AmdB)/L; + + % fit model + + [AmdB_ res fvec fvec_ amps] = piecewise_model(AmdB, Wo); + fvec_log = [fvec_log; fvec]; + amps_log = [amps_log; amps]; + + model_(f,1) = Wo; model_(f,2) = L; model_(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end + +endfunction + + +% early test, devised to test rate K<->L changes along frequency axis + +function model_ = resample_half_frame_offset(model, rate_K_surface, rate_K_sample_freqs_kHz) + max_amp = 80; + [frames col] = size(model); + + % Check distortion by shifting half a frame and returning model for + % synthesis Hmm how to handle Wo? Well lets assume it's OK and + % average it. If it sounds OK then it must be OK as well and Am + % interpolation. If not then will do some more thinking. + + model_ = zeros(frames, max_amp+3); + for f=1:frames-1 + Wo = (model(f,1) + model(f+1,1))/2; + L = min(pi/Wo, max_amp-1); + rate_L_sample_freqs_kHz = (1:L)*Wo*4/pi; + + % interpolate at half frame offset + + half = 0.5*rate_K_surface(f,:) + 0.5*rate_K_surface(f+1,:); + + % back down to rate L + + AmdB_ = interp1(rate_K_sample_freqs_kHz, half, rate_L_sample_freqs_kHz, "spline", "extrap"); + + % todo a way to save all model params ... Am, Wo, L, (v?) Start with current facility then + % make it better + + model_(f,1) = Wo; model_(f,2) = L; model_(f,3:(L+2)) = 10 .^ (AmdB_(1:L)/20); + end +endfunction + + +% vq search with optional closed loop mean estimation, turns out this gives +% identical results to extracting the mean externally + +function [mse_list index_list] = search_vq2(vq, target, m, closed_loop_dc = 0) + + [Nvec order] = size(vq); + + mse = zeros(1, Nvec); + + % find mse for each vector + + for i=1:Nvec + if closed_loop_dc + sum(target - vq(i,:)) + g = sum(target - vq(i,:))/order; + mse(i) = sum((target - vq(i,:) - g) .^2); + else + mse(i) = sum((target - vq(i,:)) .^2); + end + end + + % sort and keep top m matches + + [mse_list index_list ] = sort(mse); + + mse_list = mse_list(1:m); + index_list = index_list(1:m); + +endfunction + + +% helper function to plot surfaces + +function plot_dft_surface(surface) + [frames K] = size(surface); + + dft_surface = zeros(frames,K); + for k=1:K + dft_surface(:,k) = fft(surface(:,k).*hanning(frames)); + end + + % Set up a meaninful freq axis. We only need real side. Sample rate + % (frame rate) Fs=100Hz + + Fs = 100; dF = Fs/frames; + mesh(1:K, (1:frames/2)*dF, 20*log10(abs(dft_surface(1:frames/2,:,:)))); +endfunction + diff --git a/codec2/branches/0.7/octave/newamp1_compare.m b/codec2/branches/0.7/octave/newamp1_compare.m new file mode 100644 index 00000000..eac9ecde --- /dev/null +++ b/codec2/branches/0.7/octave/newamp1_compare.m @@ -0,0 +1,56 @@ +% newamp1_compare.m +% +% Copyright David Rowe 2016 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Compare model, Wo, and voicing files, used for checking refactoring and C port + + +function newamp1_compare(prefixa, prefixb) + autotest; + + frames = 100; + a = load_params(prefixa, frames); + b = load_params(prefixb, frames); + + check(a.Am, b.Am, 'Am'); + check(a.Hm, b.Hm, 'Hm'); + check(a.Wo, b.Wo, 'Wo'); + check(a.v, b.v, 'v'); + + figure(1); clf; plot(a.v); hold on; plot(a.v-b.v,'r'); hold off; +endfunction + + +function params = load_params(prefix, frames) + max_amp = 80; + fft_enc = 512; + + Am_out_name = sprintf("%s_am.out", prefix); + fam = fopen(Am_out_name,"rb"); + Wo_out_name = sprintf("%s_Wo.out", prefix); + fWo = fopen(Wo_out_name,"rb"); + Hm_out_name = sprintf("%s_hm.out", prefix); + fhm = fopen(Hm_out_name,"rb"); + + % load up values from binary files + + params.Am = zeros(frames, max_amp); + params.Wo = zeros(frames, 1); + params.v = zeros(frames, 1); + params.Hm = zeros(frames, max_amp); + for f=1:frames + params.Am(f,:) = fread(fam, max_amp, "float32"); + params.Wo(f) = fread(fWo, 1, "float32"); + params.Hm(f,:) = fread(fhm, max_amp, "float32"); + end + + fclose(fam); fclose(fWo); fclose(fhm); + + % voicing is a text file + + v_out_name = sprintf("%s_v.txt", prefix); + params.v = load(v_out_name); + +endfunction diff --git a/codec2/branches/0.7/octave/newamp1_fbf.m b/codec2/branches/0.7/octave/newamp1_fbf.m new file mode 100644 index 00000000..82c98188 --- /dev/null +++ b/codec2/branches/0.7/octave/newamp1_fbf.m @@ -0,0 +1,178 @@ +% newamp1_fbf.m +% +% Copyright David Rowe 2016 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Interactive Octave script to explore frame by frame operation of new amplitude +% modelling model. +% +% Usage: +% Make sure codec2-dev is compiled with the -DDUMP option - see README for +% instructions. +% ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --dump hts1a +% $ cd ~/codec2-dev/octave +% octave:14> newamp1_fbf("../build_linux/src/hts1a",50) + + +function newamp1_fbf(samname, f=73, varargin) + more off; + + newamp; + melvq; + + Fs = 8000; rate_K_sample_freqs_kHz = [0.1:0.1:4]; K = length(rate_K_sample_freqs_kHz); + quant_en = 0; vq_search = "mse"; + + % optional full band VQ + + ind = arg_exists(varargin, "vq"); + if ind + quant_en = 1; + vq_filename = varargin{ind+1}; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 1; vq_en = vq_cols; + end + + % optional split VQ low freq quantiser + + ind = arg_exists(varargin, "vql"); + if ind + quant_en = 1; + vq_filename = varargin{ind+1}; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 1; vq_en = vq_st + vq_cols - 1; + end + + % optional split VQ high freq quantiser + + ind = arg_exists(varargin, "vqh"); + if ind + quant_en = 1; + vq_filename = varargin{ind+1}; + x = load(vq_filename); vq = x.vq; + [vq_rows vq_cols] = size(vq); vq_st = 11; vq_en = K; + end + + % different vq search algorithms + + ind = arg_exists(varargin, "vq_search"); + if ind + vq_search = varargin{ind+1}; + end + + fit_order = 0; + ind = arg_exists(varargin, "noslope"); + if ind + fit_order = 1; + end + + if quant_en + printf("quant_en: %d vq_filename: %s vq_st: %d vq_en: %d vq_search: %s\n", + quant_en, vq_filename, vq_st, vq_en, vq_search); + end + + % load up text files dumped from c2sim --------------------------------------- + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + [frames tmp] = size(model); + + % Keyboard loop -------------------------------------------------------------- + + k = ' '; + do + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + figure(1); clf; plot(s); axis([1 length(s) -20000 20000]); + + Wo = model(f,1); L = model(f,2); Am = model(f,3:(L+2)); AmdB = 20*log10(Am); + Am_freqs_kHz = (1:L)*Wo*4/pi; + + % remove constant gain term + + rate_K_vec = resample_const_rate_f(model(f,:), rate_K_sample_freqs_kHz, Fs); + if fit_order == 0 + slope = 0; b = mean(rate_K_vec); + rate_K_vec_fit = rate_K_vec - b; + end + + % plots ---------------------------------- + + figure(2); clf; + plot((1:L)*Wo*4000/pi, AmdB,";AmdB;g+-"); + axis([1 4000 -20 80]); + hold on; + plot(rate_K_sample_freqs_kHz*1000, rate_K_vec, ";rate K;b+-"); + + if quant_en + target = rate_K_vec_fit(vq_st:vq_en); + + if strcmp(vq_search, "mse") + [idx contrib errors test_ g mg sl] = vq_search_mse(vq, target); + rate_K_surface_fit_(f, vq_st:vq_en) = contrib; + end + + if strcmp(vq_search, "slope") + [idx contrib errors test_ g mg sl] = vq_search_slope(vq, target); + rate_K_surface_fit_(f, vq_st:vq_en) = contrib; + end + + rate_K_vec_ = rate_K_vec_fit; rate_K_vec_(vq_st:vq_en) = contrib; + rate_K_vec_ += b; + [model_ AmdB_] = resample_rate_L(model(f,:), rate_K_vec_, rate_K_sample_freqs_kHz, Fs); + AmdB_ = AmdB_(1:L); + + sdL = std(AmdB - AmdB_); + %printf("f: %d mn_ind: %d g: %3.2f sdK: %3.2f sdL: %3.2f\n", + % f, mn_ind, g(mn_ind), error(mn_ind), sdL); + + plot(rate_K_sample_freqs_kHz(vq_st:vq_en)*1000, target - contrib, ";diff;k+-"); + plot((1:L)*Wo*4000/pi, AmdB_,";AmdB bar;r+-"); + hold off; + + end + + % interactive menu ------------------------------------------ + + printf("\rframe: %d menu: n-next b-back q-quit m-show_quant[%d]", f, quant_en); + fflush(stdout); + k = kbhit(); + + if k == 'm' + quant_en++; + if quant_en == 2 + quant_en = 0; + end + endif + if k == 'n' + f = f + 1; + endif + if k == 'b' + f = f - 1; + endif + if k == 'o' + fit_order++; + if fit_order == 2 + fit_order = 0; + end + endif + until (k == 'q') + printf("\n"); + +endfunction + + +function ind = arg_exists(v, str) + ind = 0; + for i=1:length(v) + if strcmp(v{i}, str) + ind = i; + end + end +endfunction + + diff --git a/codec2/branches/0.7/octave/newamp_batch.m b/codec2/branches/0.7/octave/newamp_batch.m new file mode 100644 index 00000000..72fd8374 --- /dev/null +++ b/codec2/branches/0.7/octave/newamp_batch.m @@ -0,0 +1,112 @@ +% newamp_batch.m +% +% Copyright David Rowe 2015 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Octave script to batch process model parameters using the new +% amplitude model. Used for generating samples we can listen to. +% +% Usage: +% ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --dump hts1a +% $ cd ~/codec2-dev/octave +% octave:14> newamp_batch("../build_linux/src/hts1a") +% ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --amread hts1a_am.out -o - | play -t raw -r 8000 -s -2 - +% Or with a little more processing: +% codec2-dev/build_linux/src$ ./c2sim ../../raw/hts2a.raw --amread hts2a_am.out --awread hts2a_aw.out --phase0 --postfilter --Woread hts2a_Wo.out -o - | play -q -t raw -r 8000 -s -2 - + + +% process a whole file and write results + +function [dk_log D1_log] = newamp_batch(samname, optional_Am_out_name, optional_Aw_out_name) + newamp; + more off; + + max_amp = 80; + k = 10; + decimate = 4; + dec_in_time = 1; + dec_in_freq = 1; + decimate = 4; + synth_phase = 1; + vq_en = 1; + dk_log = []; D1_log = []; + train = 0; + Wo_quant = 1; + ind_log = []; + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + [frames nc] = size(model); + model_ = zeros(frames, nc); + non_masked_m = zeros(frames,max_amp); + + voicing_name = strcat(samname,"_pitche.txt"); + voicing = zeros(1,frames); + if exist(voicing_name, "file") == 2 + pitche = load(voicing_name); + voicing = pitche(:, 3); + end + + if vq_en + load vq; + end + + % encoder loop ------------------------------------------------------ + + sd_sum = 0; + for f=1:frames + printf("%d ", f); + + Wo = model(f,1); + L = min([model(f,2) max_amp-1]); + + if Wo_quant + ind_Wo = encode_log_Wo(Wo, 6); + Wo = decode_log_Wo(ind_Wo, 6); + L = floor(pi/Wo); + L = min([L max_amp-1]); + end + + model_(f,1) = Wo; + model_(f,2) = L; + model_(f,3:(L+2)) = Am = model(f,3:(L+2)); + + AmdB = 20*log10(Am); + + % find mask + + mask_sample_freqs_kHz = (1:L)*Wo*4/pi; + maskdB = mask_model(AmdB, Wo, L); + + maskdB_ = maskdB; + if dec_in_freq + if vq_en + [maskdB_ tmp1 D dk_ D1_ ind_vq] = decimate_in_freq(maskdB, 1, k, vq); + else + [maskdB_ tmp1 D dk_ D1_] = decimate_in_freq(maskdB, 1, k); + end + dk_log = [dk_log; dk_]; + D1_log = [D1_log; D1_]; + end + %maskdB_pf = maskdB_*1.5; + %maskdB_pf += max(maskdB_) - max(maskdB_pf); + + % log info for bit stream + + ind_log = [ind_log; ind_Wo voicing(f) (ind_vq-1) 0]; + + %sd_sum += sum(maskdB_ - maskdB); + + Am_ = zeros(1,max_amp); + Am_ = 10 .^ (maskdB_(1:L)/20); + model_(f,3:(L+2)) = Am_; + end + + bit_stream_name = strcat(samname,".bit"); + bits_per_param = [6 1 8 8 4 1]; + write_bit_stream_file(bit_stream_name, ind_log, bits_per_param); + decode_from_bit_stream(samname); + +endfunction + diff --git a/codec2/branches/0.7/octave/newamp_fbf.m b/codec2/branches/0.7/octave/newamp_fbf.m new file mode 100644 index 00000000..c3d1bb63 --- /dev/null +++ b/codec2/branches/0.7/octave/newamp_fbf.m @@ -0,0 +1,207 @@ +% newamp_fbf.m +% +% Copyright David Rowe 2015 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Interactive Octave script to explore frame by frame operation of new amplitude +% modelling model. +% +% Usage: +% Make sure codec2-dev is compiled with the -DDUMP option - see README for +% instructions. +% ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --dump hts1a +% $ cd ~/codec2-dev/octave +% octave:14> newamp_fbf("../build_linux/src/hts1a",50) + + + +function newamp_fbf(samname, f=10) + newamp; + more off; + plot_spectrum = 1; + dec_in_freq = 1; + dec_in_time = 0; + vq_en = 0; + mask_en = 0; + + % load up text files dumped from c2sim --------------------------------------- + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + [frames tmp] = size(model); + + load vq; + + % Keyboard loop -------------------------------------------------------------- + + k = ' '; + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + size(s); + plot(s); + axis([1 length(s) -20000 20000]); + + figure(2); + clf; + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + + axis([1 4000 -20 80]); + hold on; + if plot_spectrum + plot((1:L)*Wo*4000/pi, AmdB,";Am;r"); + plot((1:L)*Wo*4000/pi, AmdB,"r+"); + end + + [maskdB Am_freqs_kHz] = mask_model(AmdB, Wo, L); + %a_non_masked_m = find(AmdB > maskdB); + %maskdB = maskdB - 6; + %maskdB(a_non_masked_m) = maskdB(a_non_masked_m) + 6; + %plot(Am_freqs_kHz*1000, maskdB, ';mask;g'); + + if mask_en + AmdB_ = maskdB; + else + AmdB_ = AmdB; + end + if dec_in_freq + [tmp1 tmp2 D] = decimate_in_freq(AmdB, 0); + if vq_en + [AmdB_ AmdB_cyclic D_cyclic dk_] = decimate_in_freq(AmdB, 1, 10, vq); + else + [AmdB_ AmdB_cyclic D_cyclic dk_] = decimate_in_freq(AmdB_, 1, 10); + end + + plot(Am_freqs_kHz*1000, AmdB_cyclic, ';mask cyclic;b'); + plot(Am_freqs_kHz*1000, AmdB_, ';mask trunc;c'); + AmdB_pf = AmdB_*(1.5); + AmdB_pf += mean(AmdB) - mean(AmdB_pf); + %max(AmdB_pf)-max(AmdB_) + %AmdB_pf -= max(AmdB_pf)-max(AmdB_); + end + + %AmdB_pf = AmdB_*(1.5); + %AmdB_pf += mean(AmdB) - mean(AmdB_pf); + AmdB_pf = AmdB_; + plot(Am_freqs_kHz*1000, AmdB_pf, ';mask trunc pf;g'); + + % Optional decimated parameters + % need to general model_ parameters either side + + if dec_in_time + decimate = 4; + model_ = set_up_model_(model, f, decimate, vq_en, vq); + maskdB_dit = decimate_frame_rate(model_, decimate, f, frames, Am_freqs_kHz); + plot(Am_freqs_kHz*1000, maskdB_dit, ';mask dit;b'); + end + + hold off; + + if dec_in_freq + % lets get a feel for the "spectrum" of the smoothed spectral envelope + % this will give us a feel for how hard it is to code, ideally we would like + % just a few coefficents to be non-zero + + figure(3) + clf + + en = L/2+1; + stem(D(2:en),'g') + hold on; + stem(D_cyclic(2:en),'b') + hold off; + + % let plot the cumulative amount of energy in each DFT + + figure(4) + clf + plot(cumsum(D(2:en)/sum(D(2:en))),';cumsum;g'); + hold on; + plot(cumsum(D_cyclic(2:en)/sum(D_cyclic(2:en))),';cumsum cyclic;b'); + hold off; + axis([1 L 0 1]) + + figure(5) + clf + stem(dk_) + end + + % interactive menu ------------------------------------------ + + printf("\rframe: %d menu: n-next b-back q-quit m-mask_en", f); + fflush(stdout); + k = kbhit(); + + if (k == 'm') + if mask_en + mask_en = 0; + else + mask_en = 1; + end + endif + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + until (k == 'q') + printf("\n"); + +endfunction + + +function model_ = set_up_model_(model, f, decimate, vq_en, vq) + [frames nc] = size(model); + model_ = zeros(frames, nc); + left_f = decimate*floor((f-1)/decimate)+1; + right_f = left_f + decimate; + + model_(left_f,:) = set_up_maskdB_(model, left_f, vq_en, vq); + model_(right_f,:) = set_up_maskdB_(model, right_f, vq_en, vq); + + model_(f,1) = model(f,1); % Wo + model_(f,2) = model(f,2); % L +endfunction + + +function amodel_row = set_up_maskdB_(model, f, vq_en, vq) + [frames nc] = size(model); + max_amp = 80; + + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + AmdB = 20*log10(Am); + + [maskdB Am_freqs_kHz] = mask_model(AmdB, Wo, L); + a_non_masked_m = find(AmdB > maskdB); + maskdB = maskdB - 6; + maskdB(a_non_masked_m) = maskdB(a_non_masked_m) + 6; + + if 0 + if vq_en + maskdB_ = decimate_in_freq(maskdB, 1, 7, vq); + else + maskdB_ = decimate_in_freq(maskdB, 1); + end + end + + maskdB_ = maskdB; + + amodel_row = zeros(1,nc); + amodel_row(1) = Wo; + amodel_row(2) = L; + Am_ = zeros(1,max_amp); + Am_ = 10 .^ (maskdB_(1:L)/20); + amodel_row(3:(L+2)) = Am_; +endfunction diff --git a/codec2/branches/0.7/octave/nf_from_gr.m b/codec2/branches/0.7/octave/nf_from_gr.m new file mode 100644 index 00000000..3f441fc2 --- /dev/null +++ b/codec2/branches/0.7/octave/nf_from_gr.m @@ -0,0 +1,113 @@ +% nf_from_gr.m +% David Rowe Mar 2016 +% +% Calculate NF from GNU Radio output samples in +% ...IQIQ... (32 bit float) sample files +% +% 1/ Take one sample with a -100dBm input carrier +% 2/ Take another sample with no signal (just rx noise) +% 3/ Set Fs, adjust st and en to use a chunk of spectrum without too +% many birdies. + +1; + +function det_nf(p_filename, n_filename, title, Fs, st, en, Pin_dB, real_file=0) + + if real_file + % real samples files of 16 bit shorts + fs=fopen(p_filename,"rb"); + p = fread(fs,Inf,"short"); + fclose(fs); + fs=fopen(n_filename,"rb"); + pn = fread(fs,Inf,"short"); + fclose(fs); + else + % GNU radio complex file input + p = load_comp(p_filename); + pn = load_comp(n_filename); + end + + P = fft(p(1:Fs)); + N = fft(pn(1:Fs)); + + PdB = 10*log10(abs(P)); + NdB = 10*log10(abs(N)); + + figure; + clf; + + subplot(211) + plot(st:en, PdB(st:en)); + + subplot(212) + plot(st:en, NdB(st:en)); + + #{ + ------------------------------------------------------------------------ + + From Wikipedia: The Noise Figure is the difference in decibels + (dB) between the noise output of the actual receiver to the noise + output of an “ideal” receiver + + An ideal receiver would have an output noise power of: + + Nout_dB = 10log10(B) -174 + G_dB + + The -174 dBm/Hz figure is the thermal noise density at 25C, for + every 1Hz of bandwidth your will get -174dBm of noise power. It's + the lower limit set by the laws of physics. G_dB is the Rx gain. The + 10log10(B) term takes into account the bandwidth of the Rx. A wider + bandwidth means more total noise power. + + So if you have a 1Hz bandwidth, and a gain of 100dB, you would + expect Nout_NdB = 0 -174 + 100 = -74dBm at the rx output with no + signal. If you have a 1000Hz bandwidth receiver you would have NdB_out + = 20 -174 + 100 = -44dBm of noise power at the output. + + To determine Noise Figure: + 1) Sample the Rx output first with a test signal and then with noise only. + 2) Find the Rx gain using the test signal. + 3) Find the noise output power, then using the gain we can find the noise + input power. + 4) Normalise the noise input power to 1Hz noise bandwidth and + compare to the thermal noise floor. + + ---------------------------------------------------------------------------- + #} + + % variance is the power of a sampled signal + + Pout_dB = 10*log10(var(P(st:en))); % Rx output power with test signal + G_dB = Pout_dB - Pin_dB; % Gain of Rx + Nout_dB = 10*log10(var(N(st:en))); % Rx output power with noise + Nin_dB = Nout_dB - G_dB; % Rx input power with noise + No_dB = Nin_dB - 10*log10(en-st); % Rx input power with noise in 1Hz bandwidth + NF_dB = No_dB + 174; % compare to thermal noise to get NF + printf("%10s: Pin: %4.1f Pout: %4.1f G: %4.1f NF: %3.1f dB\n", title, Pin_dB, Pout_dB, G_dB, NF_dB); +endfunction + +close all; + +% HackRF -------------------------- + +p_filename = "~/Desktop/nf/hackrf_100dbm_4MHz.bin"; +n_filename = "~/Desktop/nf/hackrf_nosignal_4MHz.bin"; +det_nf(p_filename, n_filename, "HackRF", 4E6, 180E3, 600E3, -100); + +% RTL-SDR -------------------------- + +p_filename = "~/Desktop/nf/neg100dBm_2MHz.bin"; +n_filename = "~/Desktop/nf/nosignal_2MHz.bin"; +det_nf(p_filename, n_filename, "RTL-SDR", 2E6, 100E3, 300E3, -100); + +% AirSpy ------------------------- + +p_filename = "~/Desktop/nf/airspy_100dbm_2.5MSPS.bin"; +n_filename = "~/Desktop/nf/airspy_nosig_2.5MSPS.bin"; +det_nf(p_filename, n_filename, "AirSpy", 2.5E6, 100E3, 300E3, -100); + +% Fun Cube Dongle Pro Plus ------------------------- + +p_filename = "~/Desktop/nf/fcdpp_100dbm_192khz.bin"; +n_filename = "~/Desktop/nf/fcdpp_nosig_192khz.bin"; +det_nf(p_filename, n_filename, "FunCube PP", 192E3, 25E3, 125E3, -100); diff --git a/codec2/branches/0.7/octave/ofdm_dev.m b/codec2/branches/0.7/octave/ofdm_dev.m new file mode 100644 index 00000000..bb356754 --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_dev.m @@ -0,0 +1,997 @@ +% ofdm_dev.m +% David Rowe April 2017 +% +% Simulations used for development and testing of Rate Fs BPSK/QPSK +% OFDM modem. + +ofdm_lib; +gp_interleaver; +ldpc; + +#{ + TODO: + [ ] compute SNR and PAPR + [ ] SSB bandpass filtering + [ ] way to simulate aquisition and demod + [ ] testframe based, maybe repeat every 10 seconds + + work out which pattern we match to sync up + [ ] acquisition curves + + plot error versus freq and timing offset + + plot pro acquisition versus freq offset, timing and freq sep and together + + plot total acquist prob at various SNRs ... maybe mean number of frames to sync? + [ ] replace genie EsNo est used for ldpc dec + [ ] clean up text +#} + +function [sim_out rx states] = run_sim(sim_in) + + % set up core modem constants + + states = ofdm_init(sim_in.bps, sim_in.Rs, sim_in.Tcp, sim_in.Ns, sim_in.Nc); + ofdm_load_const; + Nbitspervocframe = 28; + + % simulation parameters and flags + + woffset = 2*pi*sim_in.foff_hz/Fs; + dwoffset = 0; + if isfield(sim_in, "dfoff_hz_per_sec") + dwoffset = 2*pi*sim_in.dfoff_hz_per_sec/(Fs*Fs); + end + EbNodB = sim_in.EbNodB; + verbose = states.verbose = sim_in.verbose; + hf_en = sim_in.hf_en; + + timing_en = states.timing_en = sim_in.timing_en; + states.foff_est_en = foff_est_en = sim_in.foff_est_en; + states.phase_est_en = phase_est_en = sim_in.phase_est_en; + if hf_en + assert(phase_est_en == 1, "\nNo point running HF simulation without phase est!!\n"); + end + if isfield(sim_in, "diversity_en") + diversity_en = sim_in.diversity_en; + else + diversity_en = 0; + end + + if verbose == 2 + printf("Rs:..........: %4.2f\n", Rs); + printf("M:...........: %d\n", M); + printf("Ncp:.........: %d\n", Ncp); + printf("bps:.........: %d\n", bps); + printf("Nbitsperframe: %d\n", Nbitsperframe); + printf("Nrowsperframe: %d\n", Nrowsperframe); + printf("Nsamperframe.: %d\n", Nsamperframe); + end + + % Important to define run time in seconds so HF model will evolve the same way + % for different pilot insertion rates. So lets work backwards from approx + % seconds in run to get Nbits, the total number of payload data bits + + Nrows = sim_in.Nsec*Rs; + Nframes = floor((Nrows-1)/Ns); + + % if we are interleaving over multiple frames, adjust Nframes so we have an integer number + % of interleaver frames in simulation + + interleave_en = 0; + if isfield(sim_in, "interleave_frames") + interleave_frames = sim_in.interleave_frames; + Nframes = interleave_frames*round(Nframes/interleave_frames); + interleave_en = 1; + end + + Nbits = Nframes * Nbitsperframe; % number of payload data bits + + Nr = Nbits/(Nc*bps); % Number of data rows to get Nbits total + + % double check if Nbits fit neatly into carriers + + assert(Nbits/(Nc*bps) == floor(Nbits/(Nc*bps)), "Nbits/(Nc*bps) must be an integer"); + + Nrp = Nr + Nframes + 1; % number of rows once pilots inserted + % extra row of pilots at end + + if verbose == 2 + printf("Nc...........: %d\n", Nc); + printf("Ns...........: %d (step size for pilots, Ns-1 data symbols between pilots)\n", Ns); + printf("Nr...........: %d\n", Nr); + printf("Nbits........: %d\n", Nbits); + printf("Nframes......: %d\n", Nframes); + if interleave_en + printf("Interleave fr: %d\n", interleave_frames); + end + printf("Nrp..........: %d (number of rows including pilots)\n", Nrp); + end + + % Optional LPDC code ----------------------------------------------- + + ldpc_en = states.ldpc_en = sim_in.ldpc_en; + if sim_in.ldpc_en + assert(bps == 2, "Only QPSK supported for LDPC so far....."); + HRA = sim_in.ldpc_code; + [aNr aNc] = size(HRA); + rate = states.rate = (aNc-aNr)/aNc; + assert(aNc == Nbitsperframe, "Dude: Num cols of LDPC HRA must == Nbitsperframe"); + [H_rows, H_cols] = Mat2Hrows(HRA); + code_param.H_rows = H_rows; + code_param.H_cols = H_cols; + code_param.P_matrix = []; + code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix ); + code_param.code_bits_per_frame = aNc; + assert(aNr == Nbitsperframe*rate); + + modulation = states.ldpc_modulation = 'QPSK'; + mapping = states.ldpc_mapping = 'gray'; + demod_type = states.ldpc_demod_type = 0; + decoder_type = states.ldpc_decoder_type = 0; + max_iterations = states.ldpc_max_iterations = 100; + + code_param.S_matrix = CreateConstellation( modulation, 4, mapping ); + + states.code_param = code_param; + elseif diversity_en + rate = 0.5; + else + rate = 1; + end + + % set up HF model --------------------------------------------------------------- + + if hf_en + + % some typical values, or replace with user supplied + + dopplerSpreadHz = 1.0; path_delay_ms = 1; + + if isfield(sim_in, "dopplerSpreadHz") + dopplerSpreadHz = sim_in.dopplerSpreadHz; + end + if isfield(sim_in, "path_delay_ms") + path_delay_ms = sim_in.path_delay_ms; + end + path_delay_samples = path_delay_ms*Fs/1000; + printf("Doppler Spread: %3.2f Hz Path Delay: %3.2f ms %d samples\n", dopplerSpreadHz, path_delay_ms, path_delay_samples); + + % generate same fading pattern for every run + + randn('seed',1); + + spread1 = doppler_spread(dopplerSpreadHz, Fs, Nrp*(M+Ncp)*1.1); + spread2 = doppler_spread(dopplerSpreadHz, Fs, Nrp*(M+Ncp)*1.1); + + % sometimes doppler_spread() doesn't return exactly the number of samples we need + + assert(length(spread1) >= Nrp*(M+Ncp), "not enough doppler spreading samples"); + assert(length(spread2) >= Nrp*(M+Ncp), "not enough doppler spreading samples"); + end + + % ------------------------------------------------------------------ + % simulate for each Eb/No point + % ------------------------------------------------------------------ + + for nn=1:length(EbNodB) + rand('seed',1); + randn('seed',1); + + EsNo = rate * bps * (10 .^ (EbNodB(nn)/10)); + variance = 1/(M*EsNo/2); + + Nsam = Nrp*(M+Ncp); + + % generate tx bits, optionaly LDPC encode, and modulate as QPSK symbols + % note for reasons unknown LdpcEncode() returns garbage if we use > 0.5 rather than round() + + tx_data_bits = round(rand(1,Nbits*rate)); + + tx_bits = []; tx_symbols = []; + for f=1:Nframes + st = (f-1)*Nbitsperframe*rate+1; en = st + Nbitsperframe*rate - 1; + if ldpc_en + codeword = LdpcEncode(tx_data_bits(st:en), code_param.H_rows, code_param.P_matrix); + elseif diversity_en + % Nc carriers, so Nc*bps bits/row coded, or Nc*bps*rate data bits that we repeat + codeword = []; + for rr=1:Ns-1 + st1 = st + (rr-1)*Nc*bps*rate; en1 = st1 + Nc*bps*rate - 1; + codeword = [codeword tx_data_bits(st1:en1) tx_data_bits(st1:en1)]; + end + assert(length(codeword) == Nbitsperframe); + else + % uncoded mode + codeword = tx_data_bits(st:en); + end + tx_bits = [tx_bits codeword]; + for b=1:2:Nbitsperframe + tx_symbols = [tx_symbols qpsk_mod(codeword(b:b+1))]; + end + end + + % optional interleaving over multiple frames + + if interleave_en + for f=1:interleave_frames:Nframes + st = (f-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe*interleave_frames/bps - 1; + tx_symbols(st:en) = gp_interleave(tx_symbols(st:en)); + end + end + + % OFDM transmitter + + tx = []; + for f=1:Nframes + st = (f-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe/bps - 1; + tx = [tx ofdm_txframe(states, tx_symbols(st:en))]; + end + + % add extra row of pilots at end, to allow one frame simulations, + % useful for development + + st = Nsamperframe*(Nframes-1)+1; en = st+Ncp+M-1; + tx = [tx tx(st:en)]; + assert(length(tx) == Nsam); + + % channel simulation --------------------------------------------------------------- + + if isfield(sim_in, "sample_clock_offset_ppm") + % todo: this only works for large ppm like 500, runs out of memory + % for small ppm + + if sim_in.sample_clock_offset_ppm + timebase = floor(abs(1E6/sim_in.sample_clock_offset_ppm)); + if sim_in.sample_clock_offset_ppm > 0 + tx = resample(tx, timebase+1, timebase); + else + tx = resample(tx, timebase, timebase+1); + end + + % make sure length is correct for rest of simulation + + tx = [tx zeros(1,Nsam-length(tx))]; + tx = tx(1:Nsam); + end + end + + rx = tx; + + if hf_en + + rx = tx(1:Nsam) .* spread1(1:Nsam); + rx += [zeros(1,path_delay_samples) tx(1:Nsam-path_delay_samples)] .* spread2(1:Nsam); + + % normalise rx power to same as tx + + nom_rx_pwr = 2/(Ns*(M*M)) + Nc/(M*M); + rx_pwr = var(rx); + rx *= sqrt(nom_rx_pwr/rx_pwr); + end + + phase_offset = woffset*(1:Nsam) + 0.5*dwoffset*((1:Nsam).^2); + rx = rx .* exp(j*phase_offset); + + noise = sqrt(variance)*(0.5*randn(1,Nsam) + j*0.5*randn(1,Nsam)); + snrdB = 10*log10(var(rx)/var(noise)) + 10*log10(8000) - 10*log10(3000); + rx += noise; + + % some spare samples at end to avoid overflow as est windows may poke into the future a bit + + rx = [rx zeros(1,Nsamperframe)]; + + % bunch of logs + + phase_est_pilot_log = []; + delta_t_log = []; + timing_est_log = []; + foff_est_hz_log = []; + Nerrs_log = []; Nerrs_coded_log = []; + rx_bits = []; rx_np = []; rx_amp = []; + + % reset some states for each EbNo simulation point + + states.sample_point = states.timing_est = 1; + if timing_en == 0 + states.sample_point = Ncp; + end + states.nin = Nsamperframe; + states.foff_est_hz = 0; + + % for this simulation we "prime" buffer to allow one frame runs during development + + prx = 1; + states.rxbuf(M+Ncp+2*Nsamperframe+1:Nrxbuf) = rx(prx:Nsamperframe+2*(M+Ncp)); + prx += Nsamperframe+2*(M+Ncp); + + for f=1:Nframes + + % insert samples at end of buffer, set to zero if no samples + % available to disable phase estimation on future pilots on last + % frame of simulation + + lnew = min(Nsam-prx,states.nin); + rxbuf_in = zeros(1,states.nin); + + if lnew + rxbuf_in(1:lnew) = rx(prx:prx+lnew-1); + end + prx += states.nin; + + [arx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); + + rx_bits = [rx_bits arx_bits]; rx_np = [rx_np arx_np]; rx_amp = [rx_amp arx_amp]; + timing_est_log = [timing_est_log states.timing_est]; + delta_t_log = [delta_t_log states.delta_t]; + foff_est_hz_log = [foff_est_hz_log states.foff_est_hz]; + phase_est_pilot_log = [phase_est_pilot_log; aphase_est_pilot_log]; + end + + assert(length(rx_bits) == Nbits); + + % Optional de-interleave on rx QPSK symbols + + if interleave_en + for f=1:interleave_frames:Nframes + st = (f-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe*interleave_frames/bps - 1; + rx_np(st:en) = gp_deinterleave(rx_np(st:en)); + rx_amp(st:en) = gp_deinterleave(rx_amp(st:en)); + end + end + + % Calculate raw BER/PER stats, after pilots extracted. As we may + % have used interleaving, we qpsk_demod() here rather than using + % rx_bits from ofdm_demod() + + rx_bits = zeros(1, Nbits); + for s=1:Nbits/bps + rx_bits(2*(s-1)+1:2*s) = qpsk_demod(rx_np(s)); + end + + errors = xor(tx_bits, rx_bits); + Terrs = sum(errors); + + Tpackets = Tpacketerrs = 0; + Nvocframes = floor(Nbits/Nbitspervocframe); + for fv=1:Nvocframes + st = (fv-1)*Nbitspervocframe + 1; + en = st + Nbitspervocframe - 1; + Nvocpacketerrs = sum(xor(tx_bits(st:en), rx_bits(st:en))); + if Nvocpacketerrs + Tpacketerrs++; + end + Tpackets++; + end + + % Per-modem frame error log and optional LDPC/diversity error stats + + Terrs_coded = 0; Tpackets_coded = 0; Tpacketerrs_coded = 0; sim_out.error_positions = []; + for f=1:Nframes + st = (f-1)*Nbitsperframe+1; en = st + Nbitsperframe - 1; + Nerrs_log(f) = sum(xor(tx_bits(st:en), rx_bits(st:en))); + + st = (f-1)*Nbitsperframe/bps + 1; + en = st + Nbitsperframe/bps - 1; + r = rx_np(st:en); fade = rx_amp(st:en); + + % optional LDPC decode + + if ldpc_en + % note we put ceiling on EsNo as decoder misbehaives with high EsNo + + rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, min(EsNo,30), fade); + end + + % optional diversity demod + + if diversity_en + rx_codeword = []; + for rr=1:Ns-1 + for c=1:Nc/2 + s = (rr-1)*Nc + c; + rx_codeword = [rx_codeword qpsk_demod(r(s)+r(s+Nc/2))]; + end + end + assert(length(rx_codeword) == Nbitsperframe*rate); + end + + % running coded BER calcs + + if ldpc_en || diversity_en + + st = (f-1)*Nbitsperframe*rate + 1; + en = st + Nbitsperframe*rate - 1; + errors = xor(tx_data_bits(st:en), rx_codeword(1:Nbitsperframe*rate)); + Nerrs_coded = sum(errors); + Nerrs_coded_log(f) = Nerrs_coded; + Terrs_coded += Nerrs_coded; + sim_out.error_positions = [sim_out.error_positions errors]; + + % PER based on vocoder packet size, not sure it makes much + % difference compared to using all bits in LDPC code for + % packet + + atx_data_bits = tx_data_bits(st:en); + Nvocframes = Nbitsperframe*rate/Nbitspervocframe; + for fv=1:Nvocframes + st = (fv-1)*Nbitspervocframe + 1; + en = st + Nbitspervocframe - 1; + Nvocpacketerrs = sum(xor(atx_data_bits(st:en), rx_codeword(st:en))); + if Nvocpacketerrs + Tpacketerrs_coded++; + end + Tpackets_coded++; + end + end + end + + % print results of this simulation point to the console + + if ldpc_en || diversity_en + printf("Coded EbNodB: % -4.1f BER: %5.4f Tbits: %5d Terrs: %5d PER: %5.4f Tpackets: %5d Tpacket_errs: %5d\n", + EbNodB(nn), Terrs_coded/(Nbits*rate), Nbits*rate, Terrs_coded, + Tpacketerrs_coded/Tpackets_coded, Tpackets_coded, Tpacketerrs_coded); + end + EbNodB_raw = EbNodB(nn) + 10*log10(rate); + printf("Raw EbNodB..: % -4.1f BER: %5.4f Tbits: %5d Terrs: %5d PER: %5.4f Tpackets: %5d Tpacket_errs: %5d\n", + EbNodB_raw, Terrs/Nbits, Nbits, Terrs, + Tpacketerrs/Tpackets, Tpackets, Tpacketerrs); + + % returns results for plotting curves + + if ldpc_en || diversity_en + sim_out.ber(nn) = Terrs_coded/(Nbits*rate); + sim_out.per(nn) = Tpacketerrs_coded/Tpackets_coded; + else + sim_out.ber(nn) = Terrs/Nbits; + sim_out.per(nn) = Tpacketerrs/Tpackets; + end + + % Optional plots, mostly used with run-single + + if verbose + + figure(1); clf; + plot(rx_np,'+'); + %axis([-2 2 -2 2]); + title('Scatter'); + + figure(2); clf; + plot(phase_est_pilot_log,'g+', 'markersize', 5); + title('Phase est'); + axis([1 Nrp -pi pi]); + + figure(3); clf; + subplot(211) + stem(delta_t_log) + title('delta t'); + subplot(212) + plot(timing_est_log); + title('timing est'); + + figure(4); clf; + plot(foff_est_hz_log) + axis([1 max(Nframes,2) -3 3]); + title('Fine Freq'); + + figure(5); clf; + if ldpc_en + subplot(211) + stem(Nerrs_log/Nbitsperframe); + title("Uncoded BER/frame"); + subplot(212) + stem(Nerrs_coded_log/(Nbitsperframe*rate)); + title("Coded BER/frame"); + else + title("BER/frame"); + stem(Nerrs_log/Nbitsperframe); + end + + figure(6) + Tx = abs(fft(tx(1:Nsam).*hanning(Nsam)')); + Tx_dB = 20*log10(Tx); + dF = Fs/Nsam; + plot((1:Nsam)*dF, Tx_dB); + mx = max(Tx_dB); + axis([0 Fs/2 mx-60 mx]) + + +#{ + if hf_en + figure(4); clf; + subplot(211) + plot(abs(spread1(1:Nsam))); + %hold on; plot(abs(spread2(1:Nsam)),'g'); hold off; + subplot(212) + plot(angle(spread1(1:Nsam))); + title('spread1 amp and phase'); + end +#} + +#{ + % todo, work out a way to plot rate Fs hf model phase + if sim_in.hf_en + plot(angle(hf_model(:,2:Nc+1))); + end +#} + + + end + + end +endfunction + + +function run_single(EbNodB = 100, error_pattern_filename); + Ts = 0.018; + sim_in.Tcp = 0.002; + sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 16; sim_in.Ns = 8; + + sim_in.Nsec = (sim_in.Ns+1)/sim_in.Rs; % one frame, make sure sim_in.interleave_frames = 1 + %sim_in.Nsec = 1; + + sim_in.EbNodB = EbNodB; + sim_in.verbose = 2; + sim_in.hf_en = 0; + sim_in.foff_hz = 0; + sim_in.dfoff_hz_per_sec = 0.00; + sim_in.sample_clock_offset_ppm = 0; + + sim_in.timing_en = 1; + sim_in.foff_est_en = 1; + sim_in.phase_est_en = 1; + + load HRA_112_112.txt + sim_in.ldpc_code = HRA_112_112; + sim_in.ldpc_en = 1; + + sim_in.interleave_frames = 1; + + %sim_in.diversity_en = 1; + + sim_out = run_sim(sim_in); + + if nargin == 2 + fep = fopen(error_pattern_filename, "wb"); + fwrite(fep, sim_out.error_positions, "short"); + fclose(fep); + end + +end + + +% Plot BER and PER curves for AWGN and HF: +% +% i) BER/PER against Eb/No for various coding schemes +% ii) BER/PER against Eb/No showing Pilot/CP overhead +% iii) BER/PER against SNR, with pilot/CP overhead, comparing 700C + +function run_curves + + % waveform + + Ts = 0.018; sim_in.Tcp = 0.002; + sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 16; sim_in.Ns = 8; + + pilot_overhead = (sim_in.Ns-1)/sim_in.Ns; + cp_overhead = Ts/(Ts+sim_in.Tcp); + overhead_dB = -10*log10(pilot_overhead*cp_overhead); + + % simulation parameters + + sim_in.verbose = 0; + sim_in.foff_hz = 0; + sim_in.timing_en = 1; + sim_in.foff_est_en = 1; + sim_in.phase_est_en = 1; + load HRA_112_112.txt + sim_in.ldpc_code = HRA_112_112; + sim_in.ldpc_en = 0; + sim_in.hf_en = 0; + + sim_in.Nsec = 20; + sim_in.EbNodB = 0:8; + awgn_EbNodB = sim_in.EbNodB; + + awgn_theory = 0.5*erfc(sqrt(10.^(sim_in.EbNodB/10))); + awgn = run_sim(sim_in); + sim_in.ldpc_en = 1; awgn_ldpc = run_sim(sim_in); + + % Note for HF sim you really need >= 60 seconds (at Rs-50) to get sensible results c.f. theory + + sim_in.hf_en = 1; sim_in.ldpc_en = 0; + sim_in.Nsec = 60; + sim_in.EbNodB = 4:2:14; + + EbNoLin = 10.^(sim_in.EbNodB/10); + hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + hf = run_sim(sim_in); + sim_in.diversity_en = 1; hf_diversity = run_sim(sim_in); sim_in.diversity_en = 0; + sim_in.ldpc_en = 1; hf_ldpc = run_sim(sim_in); + + % try a few interleavers + + sim_in.interleave_frames = 1; hf_ldpc_1 = run_sim(sim_in); + sim_in.interleave_frames = 8; hf_ldpc_8 = run_sim(sim_in); + sim_in.interleave_frames = 16; hf_ldpc_16 = run_sim(sim_in); + sim_in.interleave_frames = 32; hf_ldpc_32 = run_sim(sim_in); + + % Rate Fs modem BER curves of various coding schemes + + figure(1); clf; + semilogy(awgn_EbNodB, awgn_theory,'b+-;AWGN theory;'); + hold on; + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF theory;'); + semilogy(awgn_EbNodB, awgn.ber,'r+-;AWGN;'); + semilogy(sim_in.EbNodB, hf.ber,'r+-;HF;'); + semilogy(sim_in.EbNodB, hf_diversity.ber,'ro-;HF diversity;'); + semilogy(awgn_EbNodB, awgn_ldpc.ber,'c+-;AWGN LDPC (224,112);'); + semilogy(sim_in.EbNodB, hf_ldpc.ber,'c+-;HF LDPC (224,112);'); + semilogy(sim_in.EbNodB, hf_ldpc_1.ber,'m+-;HF LDPC (224,112) interleave 1;'); + semilogy(sim_in.EbNodB, hf_ldpc_8.ber,'g+-;HF LDPC (224,112) interleave 8;'); + semilogy(sim_in.EbNodB, hf_ldpc_16.ber,'k+-;HF LDPC (224,112) interleave 16;'); + semilogy(sim_in.EbNodB, hf_ldpc_32.ber,'k+-;HF LDPC (224,112) interleave 32;'); + hold off; + axis([0 14 1E-3 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southwest"); + title('Rate Fs modem BER for various FEC coding schemes'); + print('-deps', '-color', "ofdm_dev_ber_coding.eps") + + awgn_per_theory = 1 - (1-awgn_theory).^28; + hf_per_theory = 1 - (1-hf_theory).^28; + + % Rate Fs modem PER curves of various coding schemes + + figure(2); clf; + semilogy(awgn_EbNodB, awgn_per_theory,'b+-;AWGN theory;'); + hold on; + semilogy(sim_in.EbNodB, hf_per_theory,'b+-;HF theory;'); + semilogy(awgn_EbNodB, awgn.per,'r+-;AWGN;'); + semilogy(sim_in.EbNodB, hf.per,'r+-;HF sim;'); + semilogy(sim_in.EbNodB, hf_diversity.per,'ro-;HF diversity;'); + semilogy(awgn_EbNodB, awgn_ldpc.per,'c+-;AWGN LDPC (224,112);'); + semilogy(sim_in.EbNodB, hf_ldpc.per,'c+-;HF LDPC (224,112);'); + semilogy(sim_in.EbNodB, hf_ldpc_1.per,'m+-;HF LDPC (224,112) interleave 1;'); + semilogy(sim_in.EbNodB, hf_ldpc_8.per,'g+-;HF LDPC (224,112) interleave 8;'); + semilogy(sim_in.EbNodB, hf_ldpc_16.per,'ko-;HF LDPC (224,112) interleave 16;'); + semilogy(sim_in.EbNodB, hf_ldpc_32.per,'k+-;HF LDPC (224,112) interleave 32;'); + hold off; + axis([0 14 1E-2 1]) + xlabel('Eb/No (dB)'); + ylabel('PER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southwest"); + title('Rate Fs modem PER for various FEC coding schemes'); + print('-deps', '-color', "ofdm_dev_per_coding.eps") + + % Rate Fs modem pilot/CP overhead BER curves + + figure(3); clf; + semilogy(awgn_EbNodB, awgn_theory,'b+-;AWGN theory;'); + hold on; + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF theory;'); + semilogy(awgn_EbNodB+overhead_dB, awgn_theory,'g+-;AWGN lower bound pilot + CP;'); + semilogy(sim_in.EbNodB+overhead_dB, hf_theory,'g+-;HF lower bound pilot + CP;'); + semilogy(awgn_EbNodB+overhead_dB, awgn.ber,'r+-;AWGN sim;'); + semilogy(sim_in.EbNodB+overhead_dB, hf.ber,'r+-;HF sim;'); + hold off; + axis([0 14 1E-3 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southwest"); + title('Rate Fs modem BER Pilot/Cyclic Prefix overhead'); + print('-deps', '-color', "ofdm_dev_ber_overhead.eps") + + % Rate Fs modem pilot/CP overhead PER curves + + figure(4); clf; + semilogy(awgn_EbNodB, awgn_per_theory,'b+-;AWGN theory;','markersize', 10, 'linewidth', 2); + hold on; + semilogy(sim_in.EbNodB, hf_per_theory,'b+-;HF theory;','markersize', 10, 'linewidth', 2); + semilogy(awgn_EbNodB+overhead_dB, awgn_per_theory,'g+-;AWGN lower bound pilot + CP;','markersize', 10, 'linewidth', 2); + semilogy(sim_in.EbNodB+overhead_dB, hf_per_theory,'g+-;HF lower bound pilot + CP;','markersize', 10, 'linewidth', 2); + semilogy(awgn_EbNodB+overhead_dB, awgn.per,'r+-;AWGN sim;','markersize', 10, 'linewidth', 2); + semilogy(sim_in.EbNodB+overhead_dB, hf.per,'r+-;HF sim;','markersize', 10, 'linewidth', 2); + hold off; + axis([0 14 1E-2 1]) + xlabel('Eb/No (dB)'); + ylabel('PER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southwest"); + title('Rate Fs modem PER Pilot/Cyclic Prefix overhead'); + print('-deps', '-color', "ofdm_dev_per_overhead.eps") + + % SNR including pilots, CP, and 700C est + + snr_awgn_theory = awgn_EbNodB + 10*log10(700/3000); + snr_hf_theory = sim_in.EbNodB + 10*log10(700/3000); + snr_awgn = snr_awgn_theory + overhead_dB; + snr_hf = sim_in.EbNodB + 10*log10(700/3000) + overhead_dB; + + % est 700C: 2/6 symbols are pilots, 1dB implementation loss + + snr_awgn_700c = awgn_EbNodB + 10*log10(700/3000) + 10*log10(6/4) + 1; + snr_hf_700c = sim_in.EbNodB + 10*log10(700/3000) + 10*log10(6/4) + 1; + + figure(5); clf; + semilogy(snr_awgn_theory, awgn_theory,'b+-;AWGN theory;','markersize', 10, 'linewidth', 2); + hold on; + semilogy(snr_awgn_700c, awgn_theory,'g+-;AWGN 700C;','markersize', 10, 'linewidth', 2); + semilogy(snr_hf_700c, hf_diversity.ber,'go-;HF 700C;','markersize', 10, 'linewidth', 2); + semilogy(snr_hf_theory, hf_theory,'b+-;HF theory;','markersize', 10, 'linewidth', 2); + semilogy(snr_awgn, awgn_ldpc.ber,'c+-;AWGN LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(snr_hf, hf_ldpc.ber,'c+-;HF LDPC (224,112);','markersize', 10, 'linewidth', 2); + semilogy(snr_hf, hf_diversity.ber,'bo-;HF diversity;','markersize', 10, 'linewidth', 2); + semilogy(snr_hf, hf_ldpc_16.ber,'k+-;HF LDPC (224,112) interleave 16;','markersize', 10, 'linewidth', 2); + hold off; + axis([-5 8 1E-3 2E-1]) + xlabel('SNR (3000Hz noise BW) (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southwest"); + title('Rate Fs modem BER versus SNR including pilot/CP overhead'); + print('-deps', '-color', "ofdm_dev_ber_snr.eps") + +end + + +% Plot BER and PER curves for AWGN and HF with various estimators + +function run_curves_estimators + + Nsec_awgn = 20; + Nsec_hf = 60; + + % waveform + + Ts = 0.018; sim_in.Tcp = 0.002; + sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 16; sim_in.Ns = 8; + + % simulation parameters + + sim_in.verbose = 0; sim_in.foff_hz = 0; sim_in.ldpc_en = 0; + + sim_in.phase_est_en = 1; + sim_in.timing_en = sim_in.foff_est_en = 0; + + % AWGN simulations + + sim_in.hf_en = 0; sim_in.Nsec = Nsec_awgn; sim_in.EbNodB = 0:2:6; + sim_in.timing_en = sim_in.foff_est_en = 0; + + awgn_EbNodB = sim_in.EbNodB; + awgn_theory = 0.5*erfc(sqrt(10.^(sim_in.EbNodB/10))); + awgn = run_sim(sim_in); + sim_in.timing_en = 1; awgn_timing = run_sim(sim_in); + sim_in.foff_est_en = 1; awgn_foff_est = run_sim(sim_in); + + sim_in.dfoff_hz_per_sec = 0.02; awgn_dfoff = run_sim(sim_in); + + % HF simulations + + sim_in.hf_en = 1; sim_in.Nsec = Nsec_hf; sim_in.EbNodB = 4:2:8; + sim_in.timing_en = sim_in.foff_est_en = 0; + + EbNoLin = 10.^(sim_in.EbNodB/10); + hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + hf = run_sim(sim_in); + sim_in.timing_en = 1; hf_timing = run_sim(sim_in); + sim_in.timing_en = 0; sim_in.foff_est_en = 1; hf_foff_est = run_sim(sim_in); + sim_in.timing_en = 1; hf_timing_foff_est = run_sim(sim_in); + + sim_in.dfoff_hz_per_sec = 0.02; hf_dfoff = run_sim(sim_in); sim_in.dfoff_hz_per_sec = 0.0; + + figure(1); clf; + semilogy(awgn_EbNodB, awgn_theory,'b+-;AWGN theory;'); + hold on; + semilogy(awgn_EbNodB, awgn.ber,'r+-;AWGN phase;'); + semilogy(awgn_EbNodB, awgn_timing.ber,'go-;AWGN phase+timing;'); + semilogy(awgn_EbNodB, awgn_foff_est.ber,'d+-;AWGN phase+timing+foff_est;'); + semilogy(awgn_EbNodB, awgn_dfoff.ber,'m+-;AWGN all + 0.02Hz/s drift;'); + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF theory;'); + semilogy(sim_in.EbNodB, hf.ber,'r+-;HF phase;'); + semilogy(sim_in.EbNodB, hf_timing.ber,'go-;HF phase+timing;'); + semilogy(sim_in.EbNodB, hf_timing_foff_est.ber,'kd-;HF phase+foff_est;'); + semilogy(sim_in.EbNodB, hf_foff_est.ber,'c+-;HF phase+timing+foff_est;'); + semilogy(sim_in.EbNodB, hf_dfoff.ber,'m+-;HF + 0.02Hz/s drift;'); + hold off; + axis([0 8 5E-3 1E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southeast"); + title('Rate Fs modem BER with estimators'); + print('-deps', '-color', "ofdm_dev_estimators.eps") + + % Simulate different HF path delays + + sim_in.hf_en = 1; sim_in.Nsec = Nsec_hf; sim_in.EbNodB = 4:2:8; + sim_in.timing_en = sim_in.foff_est_en = 0; + + sim_in.path_delay_ms = 0; hf0 = run_sim(sim_in); + sim_in.path_delay_ms = 0.5; hf500us = run_sim(sim_in); + sim_in.path_delay_ms = 1; hf1ms = run_sim(sim_in); + sim_in.path_delay_ms = 2; hf2ms = run_sim(sim_in); + + figure(2); clf; + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF theory;'); + hold on; + semilogy(sim_in.EbNodB, hf0.ber,'r+-;HF phase 0 ms;'); + semilogy(sim_in.EbNodB, hf500us.ber,'g+-;HF phase 0.5 ms;'); + semilogy(sim_in.EbNodB, hf1ms.ber,'c+-;HF phase 1 ms;'); + semilogy(sim_in.EbNodB, hf2ms.ber,'k+-;HF phase 2 ms;'); + hold off; + axis([3 9 1E-2 1E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + legend("location", "southeast"); + title('Rate Fs modem BER across HF path delay'); + print('-deps', '-color', "ofdm_dev_estimators.eps") +end + + +% Run an acquisition test, returning vectors of estimation errors + +function [delta_ct delta_foff] = acquisition_test(Ntests=10, EbNodB=100, foff_hz=0, hf_en=0, fine_en=0) + + Ts = 0.018; + sim_in.Tcp = 0.002; + sim_in.Rs = 1/Ts; sim_in.bps = 2; sim_in.Nc = 16; sim_in.Ns = 8; + + sim_in.Nsec = Ntests*(sim_in.Ns+1)/sim_in.Rs; + + sim_in.EbNodB = EbNodB; + sim_in.verbose = 2; + sim_in.hf_en = hf_en; + sim_in.foff_hz = foff_hz; + sim_in.timing_en = 0; + sim_in.foff_est_en = 0; + sim_in.phase_est_en = 0; + + [sim_out rx states] = run_sim(sim_in); + + % set up acquistion + + Nsamperframe = states.Nsamperframe; + rate_fs_pilot_samples = states.rate_fs_pilot_samples; + + % test fine or acquisition over test signal + #{ + fine: - start with coarse timing instant + - on each frame est timing a few samples about that point + - update timing instant + + corr: - where is best plcase to sample + - just before end of symbol? + - how long should sequence be? + - add extra? + - aim for last possible moment? + - man I hope IL isn't too big..... + #} + + delta_ct = []; delta_foff = []; + + if fine_en + + window_width = 5; % search +/-2 samples from current timing instant + timing_instant = Nsamperframe+1; % start at correct instant for AWGN + % start at second frame so we can search -2 ... +2 + + while timing_instant < (length(rx) - (Nsamperframe + length(rate_fs_pilot_samples) + window_width)) + st = timing_instant - ceil(window_width/2); + en = st + Nsamperframe-1 + length(rate_fs_pilot_samples) + window_width-1; + [ft_est foff_est] = coarse_sync(states, rx(st:en), rate_fs_pilot_samples); + printf("ft_est: %d timing_instant %d %d\n", ft_est, timing_instant, mod(timing_instant, Nsamperframe)); + timing_instant += Nsamperframe + ft_est - ceil(window_width/2); + delta_t = [delta_ft ft_est - ceil(window_width/2)]; + end + else + % for coarse simulation we just use contant window shifts + + st = 0.5*Nsamperframe; + en = 2.5*Nsamperframe - 1; + ct_target = Nsamperframe/2; + + for w=1:Nsamperframe:length(rx)-3*Nsamperframe + %st = w+0.5*Nsamperframe; en = st+2*Nsamperframe-1; + %[ct_est foff_est] = coarse_sync(states, rx(st:en), rate_fs_pilot_samples); + [ct_est foff_est] = coarse_sync(states, rx(w+st:w+en), rate_fs_pilot_samples); + if states.verbose + printf("ct_est: %4d foff_est: %3.1f\n", ct_est, foff_est); + end + + % valid coarse timing ests are modulo Nsamperframe + + delta_ct = [delta_ct ct_est-ct_target]; + delta_foff = [delta_foff (foff_est-foff_hz)]; + end + end + +endfunction + + +% Run some tests for various acquisition conditions. Probability of +% acquistion is what matters, e.g. if it's 50% we can expect sync +% within 2 frames +% P(t)/P(f) P(t)/P(f) +% Eb/No AWGN HF +% +/- 25Hz -1/3 1.0/0.3 0.96/0.3 +% +/- 5Hz -1/3 1.0/0.347 0.96/0.55 +% +/- 25Hz 10/10 1.00/0.92 0.99/0.77 + +function acquisition_histograms(fine_en = 0) + Fs = 8000; + Ntests = 100; + + % allowable tolerance for acquistion + + ftol_hz = 2.0; % fine freq can track this out + ttol_samples = 0.002*Fs; % 2ms, ie CP length + + % AWGN channel operating point + + [dct dfoff] = acquisition_test(Ntests, -1, -20, 0, fine_en); + + % Probability of acquistion is what matters, e.g. if it's 50% we can + % expect sync within 2 frames + + printf("AWGN P(time offset acq) = %3.2f\n", length(find (abs(dct) < ttol_samples))/length(dct)); + if fine_en == 0 + printf("AWGN P(freq offset acq) = %3.2f\n", length(find (abs(dfoff) < ftol_hz))/length(dfoff)); + end + + figure(1) + hist(dct(find (abs(dct) < ttol_samples))) + title('Coarse Timing error AWGN') + if fine_en == 0 + figure(2) + hist(dfoff) + title('Coarse Freq error AWGN') + end + + % HF channel operating point + + [dct dfoff] = acquisition_test(Ntests, 3, -20, 1, fine_en); + + printf("HF P(time offset acq) = %3.2f\n", length(find (abs(dct) < ttol_samples))/length(dct)); + if fine_en == 0 + printf("HF P(freq offset acq) = %3.2f\n", length(find (abs(dfoff) < ftol_hz))/length(dfoff)); + end + + figure(3) + hist(dct(find (abs(dct) < ttol_samples))) + title('Coarse Timing error HF') + if fine_en == 0 + figure(4) + hist(dfoff) + title('Coarse Freq error HF') + end + +endfunction + + +% --------------------------------------------------------- +% choose simulation to run here +% --------------------------------------------------------- + +format; +more off; + +init_cml('/home/david/Desktop/cml/'); + +run_single(6) +%run_curves +%run_curves_estimators +%acquisition_histograms +%acquisition_test diff --git a/codec2/branches/0.7/octave/ofdm_lib.m b/codec2/branches/0.7/octave/ofdm_lib.m new file mode 100644 index 00000000..32dd02f1 --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_lib.m @@ -0,0 +1,456 @@ +% ofdm_lib.m +% David Rowe Mar 2017 + +#{ + Library of functions that implement a BPSK/QPSK OFDM modem. Rate Fs + verison of ofdm_rs.m with OFDM based up and down conversion, and all + those nasty real-world details like fine freq, timing. +#} + + +1; + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function out = freq_shift(in, foff, Fs) + foff_rect = exp(j*2*pi*foff/Fs); + foff_phase_rect = exp(j*0); + + for r=1:length(in) + foff_phase_rect *= foff_rect; + out(r) = in(r)*foff_phase_rect; + end +endfunction + +% Correlates the OFDM pilot symbol samples with a window of received +% samples to determine the most likely timing offset. Combines two +% frames pilots so we need at least Nsamperframe+M+Ncp samples in rx. +% Also determines frequency offset at maximimum correlation. Can be +% used for acquisition (coarse timing a freq offset), and fine timing + +#{ + TODO: + [ ] attempt to speed up sync + + tis rather stateless, this current demod, which is nice + [ ] 0.5Hz grid and measure BER + + so run demod a bunch of times at different offsets + + Hmm cld also try +/- 20Hz multiples as it's aliased? + + might to use + + need metric for sync, could be callback. + [ ] or refine freq offset using pilots + [ ] different error measure that 10% maybe soft dec + + 10% very high BER + [ ] simpler CPU/DFT for freq offset estimation + + more suitable for real time implementation +#} + +function [t_est foff_est] = coarse_sync(states, rx, rate_fs_pilot_samples) + Nsamperframe = states.Nsamperframe; Fs = states.Fs; + Npsam = length(rate_fs_pilot_samples); + verbose = states.verbose; + + Ncorr = length(rx) - (Nsamperframe+Npsam) + 1; + assert(Ncorr > 0); + corr = zeros(1,Ncorr); + for i=1:Ncorr + corr(i) = abs(rx(i:i+Npsam-1) * rate_fs_pilot_samples'); + corr(i) += abs(rx(i+Nsamperframe:i+Nsamperframe+Npsam-1) * rate_fs_pilot_samples'); + end + + [mx t_est] = max(abs(corr)); + + C = abs(fft(rx(t_est:t_est+Npsam-1) .* conj(rate_fs_pilot_samples), Fs)); + C += abs(fft(rx(t_est+Nsamperframe:t_est+Nsamperframe+Npsam-1) .* conj(rate_fs_pilot_samples), Fs)); + + fmax = 30; + [mx_pos foff_est_pos] = max(C(1:fmax)); + [mx_neg foff_est_neg] = max(C(Fs-fmax+1:Fs)); + + if mx_pos > mx_neg + foff_est = foff_est_pos - 1; + else + foff_est = foff_est_neg - fmax - 1; + end + + if verbose > 1 + %printf("t_est: %d\n", t_est); + figure(7); clf; + plot(abs(corr)) + figure(8) + plot(C) + axis([0 200 0 0.4]) + end +endfunction + + +%------------------------------------------------------------- +% ofdm_init +%------------------------------------------------------------- + +#{ + Frame has Ns-1 data symbols between pilots, e.g. for Ns=3: + + PPP + DDD + DDD + PPP +#} + +function states = ofdm_init(bps, Rs, Tcp, Ns, Nc) + states.Fs = 8000; + states.bps = bps; + states.Rs = Rs; + states.Tcp = Tcp; + states.Ns = Ns; % step size for pilots + states.Nc = Nc; % Number of cols, aka number of carriers + states.M = states.Fs/Rs; + states.Ncp = Tcp*states.Fs; + states.Nbitsperframe = (Ns-1)*Nc*bps; + states.Nrowsperframe = states.Nbitsperframe/(Nc*bps); + states.Nsamperframe = (states.Nrowsperframe+1)*(states.M+states.Ncp); + + % generate same pilots each time + + rand('seed',1); + states.pilots = 1 - 2*(rand(1,Nc+2) > 0.5); + + % carrier tables for up and down conversion + + fcentre = 1500; + Nlower = floor((fcentre - Rs*Nc/2)/Rs); + w = (Nlower:Nlower+Nc+1)*2*pi*Rs/states.Fs; + W = zeros(Nc+2,states.M); + for c=1:Nc+2 + W(c,:) = exp(j*w(c)*(0:states.M-1)); + end + states.w = w; + states.W = W; + + % fine timing search +/- window_width/2 from current timing instant + + states.ftwindow_width = 11; + + % Receive buffer: D P DDD P DDD P DDD P D + % ^ + % also see ofdm_demod() ... + + states.Nrxbuf = 3*states.Nsamperframe+states.M+states.Ncp + 2*(states.M + states.Ncp); + states.rxbuf = zeros(1, states.Nrxbuf); + + % default settings on a bunch of options and states + + states.verbose = 0; + states.timing_en = 1; + states.foff_est_en = 1; + states.phase_est_en = 1; + + states.foff_est_gain = 0.01; + states.foff_est_hz = 0; + states.sample_point = states.timing_est = 1; + states.nin = states.Nsamperframe; + + % generate OFDM pilot symbol, used for timing and freq offset est + + rate_fs_pilot_samples = states.pilots * W/states.M; + states.rate_fs_pilot_samples = [rate_fs_pilot_samples(states.M-states.Ncp+1:states.M) rate_fs_pilot_samples]; + + % LDPC code is optionally enabled + + states.rate = 1.0; + states.ldpc_en = 0; + +endfunction + + + +% -------------------------------------- +% ofdm_mod - modulates one frame of bits +% -------------------------------------- + +function tx = ofdm_mod(states, tx_bits) + ofdm_load_const; + assert(length(tx_bits) == Nbitsperframe); + + % map to symbols in linear array + + if bps == 1 + tx_sym_lin = 2*tx_bits - 1; + end + if bps == 2 + for s=1:Nbitsperframe/bps + tx_sym_lin(s) = qpsk_mod(tx_bits(2*(s-1)+1:2*s)); + end + end + + tx = ofdm_txframe(states, tx_sym_lin); +endfunction + +% ----------------------------------------- +% ofdm_tx - modulates one frame of symbols +% ---------------------------------------- + +#{ + Each carrier amplitude is 1/M. There are two edge carriers that + are just tx-ed for pilots plus plus Nc continuous carriers. So + power is: + + p = 2/(Ns*(M*M)) + Nc/(M*M) + + e.g. Ns=8, Nc=16, M=144 + + p = 2/(8*(144*144)) + 16/(144*144) = 7.84-04 + +#} + +function tx = ofdm_txframe(states, tx_sym_lin) + ofdm_load_const; + assert(length(tx_sym_lin) == Nbitsperframe/bps); + + % place symbols in multi-carrier frame with pilots and boundary carriers + + tx_sym = []; s = 1; + aframe = zeros(Ns,Nc+2); + aframe(1,:) = pilots; + for r=1:Nrowsperframe + arowofsymbols = tx_sym_lin(s:s+Nc-1); + s += Nc; + aframe(r+1,2:Nc+1) = arowofsymbols; + end + tx_sym = [tx_sym; aframe]; + + % OFDM upconvert symbol by symbol so we can add CP + + tx = []; + for r=1:Ns + asymbol = tx_sym(r,:) * W/M; + asymbol_cp = [asymbol(M-Ncp+1:M) asymbol]; + tx = [tx asymbol_cp]; + end +endfunction + + +% ------------------------------------------ +% ofdm_demod - Demodulates one frame of bits +% ------------------------------------------ + +#{ + + For phase estimation we need to maintain buffer of 3 frames plus + one pilot, so we have 4 pilots total. '^' is the start of current + frame that we are demodulating. + + P DDD P DDD P DDD P + ^ + + Then add one symbol either side to account for movement in + sampling instant due to sample clock differences: + + D P DDD P DDD P DDD P D + ^ +#} + +function [rx_bits states aphase_est_pilot_log rx_np rx_amp] = ofdm_demod(states, rxbuf_in) + ofdm_load_const; + + % insert latest input samples into rxbuf + + rxbuf(1:Nrxbuf-states.nin) = rxbuf(states.nin+1:Nrxbuf); + rxbuf(Nrxbuf-states.nin+1:Nrxbuf) = rxbuf_in; + + % get latest freq offset estimate + + woff_est = 2*pi*foff_est_hz/Fs; + + % update timing estimate -------------------------------------------------- + + delta_t = 0; + if timing_en + % update timing at start of every frame + + st = M+Ncp + Nsamperframe + 1 - floor(ftwindow_width/2) + (timing_est-1); + en = st + Nsamperframe-1 + M+Ncp + ftwindow_width-1; + + ft_est = coarse_sync(states, rxbuf(st:en) .* exp(-j*woff_est*(st:en)), rate_fs_pilot_samples); + timing_est = timing_est + ft_est - ceil(ftwindow_width/2); + + if verbose > 1 + printf(" ft_est: %2d timing_est: %2d sample_point: %2d\n", ft_est, timing_est, sample_point); + end + + % Black magic to keep sample_point inside cyclic prefix. Or something like that. + + delta_t = ft_est - ceil(ftwindow_width/2); + sample_point = max(timing_est+Ncp/4, sample_point); + sample_point = min(timing_est+Ncp, sample_point); + end + + % down convert at current timing instant---------------------------------- + + % todo: this cld be more efficent, as pilot r becomes r-Ns on next frame + + rx_sym = zeros(1+Ns+1+1, Nc+2); + + % previous pilot + + st = M+Ncp + Nsamperframe + (-Ns)*(M+Ncp) + 1 + sample_point; en = st + M - 1; + + for c=1:Nc+2 + acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:)); + rx_sym(1,c) = sum(acarrier); + end + + % pilot - this frame - pilot + + for rr=1:Ns+1 + st = M+Ncp + Nsamperframe + (rr-1)*(M+Ncp) + 1 + sample_point; en = st + M - 1; + for c=1:Nc+2 + acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:)); + rx_sym(rr+1,c) = sum(acarrier); + end + end + + % next pilot + + st = M+Ncp + Nsamperframe + (2*Ns)*(M+Ncp) + 1 + sample_point; en = st + M - 1; + for c=1:Nc+2 + acarrier = rxbuf(st:en) .* exp(-j*woff_est*(st:en)) .* conj(W(c,:)); + rx_sym(Ns+3,c) = sum(acarrier); + end + + % est freq err based on all carriers ------------------------------------ + + if foff_est_en + freq_err_rect = sum(rx_sym(2,:))' * sum(rx_sym(2+Ns,:)); + + % prevent instability in atan(im/re) when real part near 0 + + freq_err_rect += 1E-6; + + %printf("freq_err_rect: %f %f angle: %f\n", real(freq_err_rect), imag(freq_err_rect), angle(freq_err_rect)); + freq_err_hz = angle(freq_err_rect)*Rs/(2*pi*Ns); + foff_est_hz = foff_est_hz + foff_est_gain*freq_err_hz; + end + + % OK - now estimate and correct phase ---------------------------------- + + aphase_est_pilot = 10*ones(1,Nc+2); + aamp_est_pilot = zeros(1,Nc+2); + for c=2:Nc+1 + + % estimate phase using average of 6 pilots in a rect 2D window centred + % on this carrier + % PPP + % DDD + % DDD + % PPP + + cr = c-1:c+1; + aphase_est_pilot_rect = sum(rx_sym(2,cr)*pilots(cr)') + sum(rx_sym(2+Ns,cr)*pilots(cr)'); + + % use next step of pilots in past and future + + aphase_est_pilot_rect += sum(rx_sym(1,cr)*pilots(cr)'); + aphase_est_pilot_rect += sum(rx_sym(2+Ns+1,cr)*pilots(cr)'); + + aphase_est_pilot(c) = angle(aphase_est_pilot_rect); + aamp_est_pilot(c) = abs(aphase_est_pilot_rect/12); + end + + % correct phase offset using phase estimate, and demodulate + % bits, separate loop as it runs across cols (carriers) to get + % frame bit ordering correct + + aphase_est_pilot_log = []; + rx_bits = []; rx_np = []; rx_amp = []; + for rr=1:Ns-1 + for c=2:Nc+1 + if phase_est_en + rx_corr = rx_sym(rr+2,c) * exp(-j*aphase_est_pilot(c)); + else + rx_corr = rx_sym(rr+2,c); + end + rx_np = [rx_np rx_corr]; + rx_amp = [rx_amp aamp_est_pilot(c)]; + if bps == 1 + abit = real(rx_corr) > 0; + end + if bps == 2 + abit = qpsk_demod(rx_corr); + end + rx_bits = [rx_bits abit]; + end % c=2:Nc+1 + aphase_est_pilot_log = [aphase_est_pilot_log; aphase_est_pilot(2:Nc+1)]; + end + + % Adjust nin to take care of sample clock offset + + nin = Nsamperframe; + if timing_en + thresh = (M+Ncp)/8; + tshift = (M+Ncp)/4; + if timing_est > thresh + nin = Nsamperframe+tshift; + timing_est -= tshift; + sample_point -= tshift; + end + if timing_est < -thresh + nin = Nsamperframe-tshift; + timing_est += tshift; + sample_point += tshift; + end + end + + states.rx_sym = rx_sym; + states.rxbuf = rxbuf; + states.nin = nin; + states.timing_est = timing_est; + states.sample_point = sample_point; + states.delta_t = delta_t; + states.foff_est_hz = foff_est_hz; +endfunction + + +% Save test bits frame to a text file in the form of a C array +% +% usage: +% ofdm_lib; test_bits_ofdm_file +% + +function test_bits_ofdm_file + + Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8; + states = ofdm_init(bps, Rs, Tcp, Ns, Nc); + ofdm_load_const; + + rand('seed',1); + test_bits_ofdm = round(rand(1,Nbitsperframe)); + + f=fopen("../src/test_bits_ofdm.h","wt"); + fprintf(f,"/* Generated by test_bits_ofdm_file() Octave function */\n\n"); + fprintf(f,"const int test_bits_ofdm[]={\n"); + for m=1:length(test_bits_ofdm)-1 + fprintf(f," %d,\n",test_bits_ofdm(m)); + endfor + fprintf(f," %d\n};\n",test_bits_ofdm(length(test_bits_ofdm))); + fclose(f); + +endfunction diff --git a/codec2/branches/0.7/octave/ofdm_load_const.m b/codec2/branches/0.7/octave/ofdm_load_const.m new file mode 100644 index 00000000..db66d6d9 --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_load_const.m @@ -0,0 +1,46 @@ +% make like C #define for ofdm modem + +Fs = states.Fs; +bps = states.bps; +Rs = states.Rs; +Tcp = states.Tcp; +Ns = states.Ns; +Nc = states.Nc; +M = states.M; +Ncp = states.Ncp; +bps = states.bps; +Nbitsperframe = states.Nbitsperframe; +Nrowsperframe = states.Nrowsperframe; +Nsamperframe = states.Nsamperframe; + +W = states.W; +w = states.w; + +timing_est = states.timing_est; +sample_point = states.sample_point; +ftwindow_width = states.ftwindow_width; + +Nrxbuf = states.Nrxbuf; +rxbuf = states.rxbuf; + +pilots = states.pilots; +rate_fs_pilot_samples = states.rate_fs_pilot_samples; + +foff_est_gain = states.foff_est_gain; +foff_est_hz = states.foff_est_hz; + +timing_en = states.timing_en; +foff_est_en = states.foff_est_en; +phase_est_en = states.phase_est_en; + +rate = states.rate; +ldpc_en = states.ldpc_en; +if ldpc_en + code_param = states.code_param; + max_iterations = states.ldpc_max_iterations; + demod_type = states.ldpc_demod_type; + decoder_type = states.ldpc_decoder_type; +end + +verbose = states.verbose; + diff --git a/codec2/branches/0.7/octave/ofdm_rs.m b/codec2/branches/0.7/octave/ofdm_rs.m new file mode 100644 index 00000000..4c89a50c --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_rs.m @@ -0,0 +1,795 @@ +% ofdm_rs.m +% David Rowe Mar 2017 +% +% Rate Rs BPSK/QPSK simulation to explore techniques for +% phase estimation over multiple carriers in HF channel. Rate +% Rs version of ofdm_fs.m + +#{ + TODO: + [X] sim pilot based phase est using known symbols + [X] test AWGN BER with averaging pilots from adj carriers + [X] refactor to insert pilot rows + [X] add border cols, not used for data + [X] centre est on current carrier, extend to > 3 + [X] test single points + + 1dB IL @ 6dB HF, 0.4 dB @ 2dB AWGN + [X] try linear interpolation + [X] try longer time windows + [X] try combining mod stripping phase est inside frame + [X] curves taking into account pilot losses + [ ] remove border carriers, interpolate edge carrier + [X] modify for QPSK +#} + +1; + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +function sim_out = run_sim(sim_in) + Rs = 100; + + bps = sim_in.bps; + EbNodB = sim_in.EbNodB; + verbose = sim_in.verbose; + hf_en = sim_in.hf_en; + hf_phase = sim_in.hf_phase; + phase_offset = sim_in.phase_offset; + + Ns = sim_in.Ns; % step size for pilots + Nc = sim_in.Nc; % Number of cols, aka number of carriers + + Nbitsperframe = (Ns-1)*Nc*bps; + Nrowsperframe = Nbitsperframe/(Nc*bps); + if verbose + printf("bps:.........: %d\n", bps); + printf("Nbitsperframe: %d\n", Nbitsperframe); + printf("Nrowsperframe: %d\n", Nrowsperframe); + end + + % Important to define run time in seconds so HF model will evolve the same way + % for different pilot insertion rates. So lets work backwards from approx + % seconds in run to get Nbits, the total number of payload data bits + + % frame has Ns-1 data symbols between pilots, e.g. for Ns=3: + % + % PPP + % DDD + % DDD + % PPP + + Nrows = sim_in.Nsec*Rs; + Nframes = floor((Nrows-1)/Ns); + Nbits = Nframes * Nbitsperframe; % number of payload data bits + + Nr = Nbits/(Nc*bps); % Number of data rows to get Nbits total + + if verbose + printf("Nc.....: %d\n", Nc); + printf("Ns.....: %d (step size for pilots, Ns-1 data symbols between pilots)\n", Ns); + printf("Nr.....: %d\n", Nr); + printf("Nbits..: %d\n", Nbits); + end + + % double check if Nbits fit neatly into carriers + + assert(Nbits/(Nc*bps) == floor(Nbits/(Nc*bps)), "Nbits/(Nc*bps) must be an integer"); + + printf("Nframes: %d\n", Nframes); + + Nrp = Nr + Nframes + 1; % number of rows once pilots inserted + % extra row of pilots at end + printf("Nrp....: %d (number of rows including pilots)\n", Nrp); + + % set up HF model + + if hf_en + + % some typical values, or replace with user supplied + + dopplerSpreadHz = 1.0; path_delay = 1E-3*Rs; + + if isfield(sim_in, "dopplerSpreadHz") + dopplerSpreadHz = sim_in.dopplerSpreadHz; + end + if isfield(sim_in, "path_delay") + path_delay = sim_in.path_delay; + end + printf("Doppler Spread: %3.2f Hz Path Delay: %3.2f symbols\n", dopplerSpreadHz, path_delay); + randn('seed',1); + spread1 = doppler_spread(dopplerSpreadHz, Rs, sim_in.Nsec*Rs*1.1); + spread2 = doppler_spread(dopplerSpreadHz, Rs, sim_in.Nsec*Rs*1.1); + + % sometimes doppler_spread() doesn't return exactly the number of samples we need + + assert(length(spread1) >= Nrp, "not enough doppler spreading samples"); + assert(length(spread2) >= Nrp, "not enough doppler spreading samples"); + end + + % construct an artificial phase countour for testing, linear across freq and time + + if sim_in.phase_test + phase_test = ones(Nrp, Nc+2); + for r=1:Nrp + for c=1:Nc+2 + phase_test(r,c) = -pi/2 + c*pi/(Nc+2) + r*0.01*2*pi; + phase_test(r,c) = phase_test(r,c) - 2*pi*floor((phase_test(r,c)+pi)/(2*pi)); + end + end + end + + % simulate for each Eb/No point ------------------------------------ + + for nn=1:length(EbNodB) + rand('seed',1); + randn('seed',1); + + EsNo = bps * (10 .^ (EbNodB(nn)/10)); + variance = 1/(EsNo/2); + noise = sqrt(variance)*(0.5*randn(Nrp,Nc+2) + j*0.5*randn(Nrp,Nc+2)); + + % generate tx bits + + tx_bits = rand(1,Nbits) > 0.5; + + % map to symbols + + if bps == 1 + tx_symb = 2*tx_bits - 1; + end + if bps == 2 + for s=1:Nbits/bps + tx_symb(s) = qpsk_mod(tx_bits(2*(s-1)+1:2*s)); + end + end + + % place symbols in multi-carrier frame with pilots and boundary carriers + + tx = []; s = 1; + for f=1:Nframes + aframe = zeros(Nrowsperframe,Nc+2); + aframe(1,:) = 1; + for r=1:Nrowsperframe + arowofsymbols = tx_symb(s:s+Nc-1); + s += Nc; + aframe(r+1,2:Nc+1) = arowofsymbols; + end + tx = [tx; aframe]; + end + tx = [tx; ones(1,Nc+2)]; % final row of pilots + [nr nc] = size(tx); + assert(nr == Nrp); + + rx = tx * exp(j*phase_offset); + + if sim_in.phase_test + rx = rx .* exp(j*phase_test); + end + + if hf_en + + % simplified rate Rs simulation model that doesn't include + % ISI, just freq filtering. + + % Note Rs carrier spacing, sample rate is Rs + + hf_model = zeros(Nr,Nc+2); phase_est = zeros(Nr,Nc); + for r=1:Nrp + for c=1:Nc+2 + w = 2*pi*c*Rs/Rs; + hf_model(r,c) = spread1(r) + exp(-j*w*path_delay)*spread2(r); + end + + if hf_phase + rx(r,:) = rx(r,:) .* hf_model(r,:); + else + rx(r,:) = rx(r,:) .* abs(hf_model(r,:)); + end + end + + % normalise power over HF simulation run + + p = sum(var(rx)); + rx *= sqrt(Nc/p); + end + + rx += noise; + + % pilot based phase est, we use known tx symbols as pilots ---------- + + rx_corr = rx; + + if sim_in.pilot_phase_est + + % est phase from pilots either side of data symbols + % adjust phase of data symbol + % demodulate and count errors of just data + + phase_est_pilot_log = 10*ones(Nrp,Nc+2); + phase_est_stripped_log = 10*ones(Nrp,Nc+2); + phase_est_log = 10*ones(Nrp,Nc+2); + for c=2:Nc+1 + for r=1:Ns:Nrp-Ns + + % estimate phase using average of 6 pilots in a rect 2D window centred + % on this carrier + % PPP + % DDD + % DDD + % PPP + + cr = c-1:c+1; + aphase_est_pilot_rect1 = sum(rx(r,cr)*tx(r,cr)'); + aphase_est_pilot_rect2 = sum(rx(r+Ns,cr)*tx(r+Ns,cr)'); + + % optionally use next step of pilots in past and future + + if sim_in.pilot_wide + if r > Ns+1 + aphase_est_pilot_rect1 += sum(rx(r-Ns,cr)*tx(r-Ns,cr)'); + end + if r < Nrp - 2*Ns + aphase_est_pilot_rect2 += sum(rx(r+2*Ns,cr)*tx(r+2*Ns,cr)'); + end + end + + % correct phase offset using phase estimate + + for rr=r+1:r+Ns-1 + a = b = 1; + if sim_in.pilot_interp + b = (rr-r)/Ns; a = 1 - b; + end + %printf("rr: %d a: %4.3f b: %4.3f\n", rr, a, b); + aphase_est_pilot = angle(a*aphase_est_pilot_rect1 + b*aphase_est_pilot_rect2); + phase_est_pilot_log(rr,c) = aphase_est_pilot; + rx_corr(rr,c) = rx(rr,c) * exp(-j*aphase_est_pilot); + end + + if sim_in.stripped_phase_est + % Optional modulation stripping feed fwd phase estimation, to refine + % pilot-based phase estimate. Doing it after pilot based phase estimation + % means we don't need to deal with ambiguity, which is difficult to handle + % in low SNR channels. + + % Use vector of 7 symbols around current data symbol. We could use a 2D + % window if we can work out how best to correct with pilot-est and avoid + % ambiguities + + for rr=r+1:r+Ns-1 + + % extract a matrix of nearby samples with pilot-based offset removed + + amatrix = rx(max(1,rr-3):min(Nrp,rr+3),c) .* exp(-j*aphase_est_pilot); + + % modulation strip and est phase + + stripped = abs(amatrix) .* exp(j*2*angle(amatrix)); + aphase_est_stripped = angle(sum(sum(stripped)))/2; + phase_est_stripped_log(rr,c) = aphase_est_stripped; + + % correct rx symbols based on both phase ests + + phase_est_log(rr,c) = angle(exp(j*(aphase_est_pilot+aphase_est_stripped))); + rx_corr(rr,c) = rx(rr,c) * exp(-j*phase_est_log(rr,c)); + end + end % sim_in.stripped_phase_est + + end % r=1:Ns:Nrp-Ns + + end % c=2:Nc+1 + end % sim_in.pilot_phase_est + + + if isfield(sim_in, "ml_pd") && sim_in.ml_pd + + % Bill's ML with pilots phase detector, does phase est and demodulation + + rx_bits = []; rx_np = []; + aframeofbits = zeros(Ns-1, Nc); + for r=1:Ns:Nrp-Ns + + % demodulate this frame, ML operates carrier by carrier + + for c=2:Nc+1 + arxcol = rx(r:r+Ns, c); + arxcol(1) = rx(r, c-1) + rx(r, c+1); + arxcol(Ns+1) = rx(r+Ns, c-1) + rx(r+Ns, c+1); + [acolofbits aphase_est] = ml_pd(rot90(arxcol), bps, [1 Ns+1]); + aframeofbits(:,c-1) = xor(acolofbits, ones(1,Ns-1)); + rx_np = [rx_np rot90(arxcol) .* exp(-j*aphase_est)]; + end + + % unpack from frame into linear array of bits + + for rr=1:Ns-1 + rx_bits = [rx_bits aframeofbits(rr,:)]; + end + + end + else + + % remove pilots to give us just data symbols and demodulate + + rx_bits = []; rx_np = []; + for r=1:Nrp + if mod(r-1,Ns) != 0 + arowofsymbols = rx_corr(r,2:Nc+1); + rx_np = [rx_np arowofsymbols]; + if bps == 1 + arowofbits = real(arowofsymbols) > 0; + end + if bps == 2 + arowofbits = zeros(1,Nc); + for c=1:Nc + arowofbits((c-1)*2+1:c*2) = qpsk_demod(arowofsymbols(c)); + end + end + rx_bits = [rx_bits arowofbits]; + end + end + end + %tx_bits + %rx_bits + assert(length(rx_bits) == Nbits); + + %phase_test + %phase_est_log + + % calculate BER stats as a block, after pilots extracted + + errors = xor(tx_bits, rx_bits); + Nerrs = sum(errors); + + printf("EbNodB: %3.2f BER: %5.4f Nbits: %d Nerrs: %d\n", EbNodB(nn), Nerrs/Nbits, Nbits, Nerrs); + + if verbose + figure(1); clf; + plot(rx_np,'+'); + axis([-2 2 -2 2]); + + if hf_en + figure(2); clf; + plot(abs(hf_model(:,2:Nc+1))); + end + + if sim_in.pilot_phase_est + figure(3); clf; + plot(phase_est_log(:,2:Nc+1),'+', 'markersize', 10); + hold on; + plot(phase_est_pilot_log(:,2:Nc+1),'g+', 'markersize', 5); + if sim_in.stripped_phase_est + plot(phase_est_stripped_log(:,2:Nc+1),'ro', 'markersize', 5); + end + if sim_in.hf_en && sim_in.hf_phase + plot(angle(hf_model(:,2:Nc+1))); + end + if sim_in.phase_test + plot(phase_test(:,2:Nc+1)); + end + axis([1 Nrp -pi pi]); + end + end + + sim_out.ber(nn) = sum(Nerrs)/Nbits; + sim_out.pilot_overhead = 10*log10(Ns/(Ns-1)); + end +endfunction + + +% Plot BER against Eb/No curves at various pilot insertion rates Ns +% using the HF multipath channel. Second set of curves includes Eb/No +% loss for pilot insertion, so small Ns means better tracking of phase +% but large pilot insertion loss + +% Target operating point Eb/No is 6dB, as this is where our rate 1/2 +% LDPC code gives good results (10% PER, 1% BER). However this means +% the Eb/No at the input is 10*log(1/2) or 3dB less, so we need to +% make sure phase est works at Eb/No = 6 - 3 = 3dB + +function run_curves_hf + sim_in.Nc = 7; + sim_in.Ns = 5; + sim_in.Nsec = 240; + sim_in.EbNodB = 1:8; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 0; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 0; + + sim_in.Ns = 5; + hf_ref_Ns_5_no_phase = run_sim(sim_in); + sim_in.Ns = 9; + hf_ref_Ns_9_no_phase = run_sim(sim_in); + + sim_in.hf_phase = 1; + sim_in.pilot_phase_est = 1; + + sim_in.Ns = 5; + hf_Ns_5 = run_sim(sim_in); + + sim_in.Ns = 9; + hf_Ns_9 = run_sim(sim_in); + + sim_in.Ns = 17; + hf_Ns_17 = run_sim(sim_in); + + figure(4); clf; + semilogy(sim_in.EbNodB, hf_ref_Ns_5_no_phase.ber,'b+-;Ns=5 HF ref no phase;'); + hold on; + semilogy(sim_in.EbNodB, hf_ref_Ns_9_no_phase.ber,'c+-;Ns=9 HF ref no phase;'); + semilogy(sim_in.EbNodB, hf_Ns_5.ber,'g+--;Ns=5;'); + semilogy(sim_in.EbNodB + hf_Ns_5.pilot_overhead, hf_Ns_5.ber,'go-;Ns=5 with pilot overhead;'); + semilogy(sim_in.EbNodB, hf_Ns_9.ber,'r+--;Ns=9;'); + semilogy(sim_in.EbNodB + hf_Ns_9.pilot_overhead, hf_Ns_9.ber,'ro-;Ns=9 with pilot overhead;'); + semilogy(sim_in.EbNodB, hf_Ns_17.ber,'k+--;Ns=17;'); + semilogy(sim_in.EbNodB + hf_Ns_17.pilot_overhead, hf_Ns_17.ber,'ko-;Ns=17 with pilot overhead;'); + hold off; + axis([1 8 4E-2 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('HF Multipath 1Hz Doppler 1ms delay'); + +end + + +% Generate HF curves for some alternative, experimental methods tested +% during development, such as interpolation, refinements using +% modulation stripping, narrow window. + +function run_curves_hf_alt + sim_in.Nc = 7; + sim_in.Ns = 5; + sim_in.Nsec = 60; + sim_in.EbNodB = 1:8; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 0; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 0; + + sim_in.Ns = 9; + hf_ref_Ns_9_no_phase = run_sim(sim_in); + + sim_in.hf_phase = 1; + sim_in.pilot_phase_est = 1; + hf_Ns_9 = run_sim(sim_in); + + sim_in.stripped_phase_est = 1; + hf_Ns_9_stripped = run_sim(sim_in); + + sim_in.stripped_phase_est = 0; + sim_in.pilot_wide = 0; + hf_Ns_9_narrow = run_sim(sim_in); + + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 1; + hf_Ns_9_interp = run_sim(sim_in); + + figure(6); clf; + semilogy(sim_in.EbNodB, hf_ref_Ns_9_no_phase.ber,'c+-;Ns=9 HF ref no phase;'); + hold on; + semilogy(sim_in.EbNodB, hf_Ns_9.ber,'r+--;Ns=9;'); + semilogy(sim_in.EbNodB, hf_Ns_9_stripped.ber,'g+--;Ns=9 stripped refinement;'); + semilogy(sim_in.EbNodB, hf_Ns_9_narrow.ber,'b+--;Ns=9 narrow;'); + semilogy(sim_in.EbNodB, hf_Ns_9_interp.ber,'k+--;Ns=9 interp;'); + hold off; + axis([1 8 4E-2 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('HF Multipath 1Hz Doppler 1ms delay'); + +end + + +% Generate HF curves for fixed Ns but different HF channels. + +function run_curves_hf_channels + sim_in.Nc = 7; + sim_in.Ns = 9; + sim_in.Nsec = 240; + sim_in.EbNodB = 1:8; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 0; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 0; + + hf_Ns_9_1hz_1ms_no_phase = run_sim(sim_in); + + sim_in.hf_phase = 1; + sim_in.pilot_phase_est = 1; + hf_Ns_9_1hz_1ms = run_sim(sim_in); + + Rs = 100; + + sim_in.dopplerSpreadHz = 1.0; + sim_in.path_delay = 500E-6*Rs; + hf_Ns_9_1hz_500us = run_sim(sim_in); + + sim_in.dopplerSpreadHz = 1.0; + sim_in.path_delay = 2E-3*Rs; + hf_Ns_9_1hz_2ms = run_sim(sim_in); + + sim_in.dopplerSpreadHz = 2.0; + sim_in.path_delay = 1E-3*Rs; + hf_Ns_9_2hz_1ms = run_sim(sim_in); + + sim_in.dopplerSpreadHz = 2.0; + sim_in.path_delay = 1E-3*Rs; + hf_Ns_9_2hz_2ms = run_sim(sim_in); + + sim_in.dopplerSpreadHz = 2.0; + sim_in.path_delay = 2E-3*Rs; + hf_Ns_9_2hz_2ms = run_sim(sim_in); + + sim_in.dopplerSpreadHz = 4.0; + sim_in.path_delay = 1E-3*Rs; + hf_Ns_9_4hz_1ms = run_sim(sim_in); + + figure(6); clf; + semilogy(sim_in.EbNodB, hf_Ns_9_1hz_1ms_no_phase.ber,'c+-;Ns=9 1Hz 1ms ref no phase;'); + hold on; + semilogy(sim_in.EbNodB, hf_Ns_9_1hz_500us.ber,'k+-;Ns=9 1Hz 500us;'); + semilogy(sim_in.EbNodB, hf_Ns_9_1hz_1ms.ber,'r+-;Ns=9 1Hz 1ms;'); + semilogy(sim_in.EbNodB, hf_Ns_9_1hz_2ms.ber,'bo-;Ns=9 1Hz 2ms;'); + semilogy(sim_in.EbNodB, hf_Ns_9_2hz_1ms.ber,'g+-;Ns=9 2Hz 1ms;'); + semilogy(sim_in.EbNodB, hf_Ns_9_2hz_2ms.ber,'mo-;Ns=9 2Hz 2ms;'); + semilogy(sim_in.EbNodB, hf_Ns_9_4hz_1ms.ber,'c+-;Ns=9 4Hz 1ms;'); + hold off; + axis([1 8 4E-2 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('HF Multipath Ns = 9'); + +end + + +% AWGN curves for BPSK and QPSK. Coded Eb/No operating point is 2dB, +% so raw BER for rate 1/2 will be -1dB + +function run_curves_awgn_bpsk_qpsk + sim_in.Nc = 7; + sim_in.Ns = 7; + sim_in.Nsec = 30; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 0; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 1; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 0; + sim_in.hf_phase = 0; + + sim_in.EbNodB = -3:5; + + ber_awgn_theory = 0.5*erfc(sqrt(10.^(sim_in.EbNodB/10))); + + sim_in.bps = 1; + awgn_bpsk = run_sim(sim_in); + sim_in.bps = 2; + awgn_qpsk = run_sim(sim_in); + + figure(5); clf; + semilogy(sim_in.EbNodB, ber_awgn_theory,'b+-;AWGN Theory;'); + hold on; + semilogy(sim_in.EbNodB, awgn_bpsk.ber,'g+-;Ns=7 BPSK;'); + semilogy(sim_in.EbNodB + awgn_bpsk.pilot_overhead, awgn_bpsk.ber,'go-;Ns=7 BPSK with pilot overhead;'); + semilogy(sim_in.EbNodB, awgn_qpsk.ber,'r+-;Ns=7 QPSK;'); + semilogy(sim_in.EbNodB + awgn_qpsk.pilot_overhead, awgn_qpsk.ber,'ro-;Ns=7 QPSK with pilot overhead;'); + hold off; + axis([-3 5 4E-3 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('AWGN'); +end + + +% HF multipath curves for BPSK and QPSK. Coded operating point is about 3dB + +function run_curves_hf_bpsk_qpsk + sim_in.Nc = 7; + sim_in.Ns = 7; + sim_in.Nsec = 120; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 1; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 1; + + sim_in.EbNodB = 1:8; + + EbNoLin = 10.^(sim_in.EbNodB/10); + hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + sim_in.bps = 1; + hf_bpsk = run_sim(sim_in); + sim_in.bps = 2; + hf_qpsk = run_sim(sim_in); + + figure(5); clf; + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF Theory;'); + hold on; + semilogy(sim_in.EbNodB, hf_bpsk.ber,'g+-;Ns=7 BPSK;'); + semilogy(sim_in.EbNodB + hf_bpsk.pilot_overhead, hf_bpsk.ber,'go-;Ns=7 BPSK with pilot overhead;'); + semilogy(sim_in.EbNodB, hf_qpsk.ber,'r+-;Ns=7 QPSK;'); + semilogy(sim_in.EbNodB + hf_qpsk.pilot_overhead, hf_qpsk.ber,'ro-;Ns=7 QPSK with pilot overhead;'); + hold off; + axis([1 8 4E-3 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('HF Multipath'); +end + + +% AWGN curves for BPSK using 3 carrier 2D matrix pilot and ML pilot + +function run_curves_awgn_ml + sim_in.bps = 1; + sim_in.Nc = 7; + sim_in.Ns = 7; + sim_in.Nsec = 10; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 1; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 1; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 0; + sim_in.hf_phase = 0; + + sim_in.EbNodB = -3:5; + + ber_awgn_theory = 0.5*erfc(sqrt(10.^(sim_in.EbNodB/10))); + + awgn_2d = run_sim(sim_in); + sim_in.pilot_phase_est = 0; + sim_in.ml_pd = 1; + awgn_ml = run_sim(sim_in); + + figure(5); clf; + semilogy(sim_in.EbNodB, ber_awgn_theory,'b+-;AWGN Theory;'); + hold on; + semilogy(sim_in.EbNodB, awgn_2d.ber,'g+-;Ns=7 3 carrier pilot BPSK;'); + semilogy(sim_in.EbNodB, awgn_ml.ber,'ro-;Ns=7 ML pilot BPSK;'); + hold off; + axis([-3 5 4E-3 5E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('AWGN'); +end + + +% HF multipath curves for ML + +function run_curves_hf_ml + sim_in.bps = 1; + sim_in.Nc = 7; + sim_in.Ns = 14; + sim_in.Nsec = 120; + sim_in.verbose = 0; + sim_in.pilot_phase_est = 1; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 1; + + sim_in.EbNodB = 1:8; + + EbNoLin = 10.^(sim_in.EbNodB/10); + hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + + hf_2d = run_sim(sim_in); + sim_in.pilot_phase_est = 0; + sim_in.ml_pd = 1; + hf_ml = run_sim(sim_in); + + figure(7); clf; + semilogy(sim_in.EbNodB, hf_theory,'b+-;HF Theory;'); + hold on; + semilogy(sim_in.EbNodB, hf_2d.ber,'g+-;Ns=7 3 carrier pilot BPSK;'); + semilogy(sim_in.EbNodB, hf_ml.ber,'ro-;Ns=7 ML pilot BPSK;'); + hold off; + axis([1 8 4E-3 2E-1]) + xlabel('Eb/No (dB)'); + ylabel('BER'); + grid; grid minor on; + legend('boxoff'); + title('HF Multipath'); +end + + + +function run_single + sim_in.bps = 2; + sim_in.Nsec = 60; + sim_in.Nc = 16; + sim_in.Ns = 8; + sim_in.EbNodB = 6; + sim_in.verbose = 1; + + sim_in.pilot_phase_est = 1; + sim_in.pilot_wide = 1; + sim_in.pilot_interp = 0; + sim_in.stripped_phase_est = 0; + sim_in.ml_pd = 0; + + sim_in.phase_offset = 0; + sim_in.phase_test = 0; + sim_in.hf_en = 1; + sim_in.hf_phase = 1; + sim_in.path_delay = 0; + + run_sim(sim_in); + + EbNoLin = 10.^(sim_in.EbNodB/10); + hf_theory = 0.5.*(1-sqrt(EbNoLin./(EbNoLin+1))); + printf("HF theory: %5.4f\n", hf_theory); +end + + +format; +more off; + +run_single +%run_curves_hf_bpsk_qpsk +%run_curves_hf_channels +%run_curves_hf_ml + + + + diff --git a/codec2/branches/0.7/octave/ofdm_rx.m b/codec2/branches/0.7/octave/ofdm_rx.m new file mode 100644 index 00000000..d108181b --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_rx.m @@ -0,0 +1,295 @@ +% ofdm_rx.m +% David Rowe April 2017 +% +% OFDM file based rx. + +#{ + TODO: + [ ] proper EsNo estimation + [ ] some sort of real time GUI display to watch signal evolving + [ ] est SNR or Eb/No of recieved signal + [ ] way to fall out of sync +#} + +function ofdm_rx(filename, interleave_frames = 1, error_pattern_filename) + ofdm_lib; + ldpc; + gp_interleaver; + more off; + + % init modem + + Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8; + states = ofdm_init(bps, Rs, Tcp, Ns, Nc); + ofdm_load_const; + states.verbose = 1; + + % Set up LDPC code + + mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray'; + demod_type = 0; decoder_type = 0; max_iterations = 100; + + EsNo = 10; % TODO: fixme + + init_cml('/home/david/Desktop/cml/'); + load HRA_112_112.txt + [code_param framesize rate] = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping); + assert(Nbitsperframe == code_param.code_bits_per_frame); + + % load real samples from file + + Ascale= 2E5*1.1491; + frx=fopen(filename,"rb"); rx = 2*fread(frx, Inf, "short")/4E5; fclose(frx); + Nsam = length(rx); Nframes = floor(Nsam/Nsamperframe); + prx = 1; + + % buffers for interleaved frames + + Nsymbolsperframe = code_param.code_bits_per_frame/bps + Nsymbolsperinterleavedframe = interleave_frames*Nsymbolsperframe + rx_np = zeros(1, Nsymbolsperinterleavedframe); + rx_amp = zeros(1, Nsymbolsperinterleavedframe); + + % OK generate tx frame for BER calcs + + rand('seed', 100); + tx_bits = []; tx_codewords = []; + for f=1:interleave_frames + atx_bits = round(rand(1,code_param.data_bits_per_frame)); + tx_bits = [tx_bits atx_bits]; + acodeword = LdpcEncode(atx_bits, code_param.H_rows, code_param.P_matrix); + tx_codewords = [tx_codewords acodeword]; + end + + % used for rx frame sync on interleaved symbols - we demod the + % entire interleaved frame to raw bits + + tx_symbols = []; + for s=1:Nsymbolsperinterleavedframe + tx_symbols = [tx_symbols qpsk_mod( tx_codewords(2*(s-1)+1:2*s) )]; + end + + tx_symbols = gp_interleave(tx_symbols); + + tx_bits_raw = []; + for s=1:Nsymbolsperinterleavedframe + tx_bits_raw = [tx_bits_raw qpsk_demod(tx_symbols(s))]; + end + + % init logs and BER stats + + rx_bits = []; rx_np_log = []; timing_est_log = []; delta_t_log = []; foff_est_hz_log = []; + phase_est_pilot_log = []; + Terrs = Tbits = Terrs_coded = Tbits_coded = Tpackets = Tpacketerrs = 0; + Nbitspervocframe = 28; + Nerrs_coded_log = Nerrs_log = []; + error_positions = []; + + % 'prime' rx buf to get correct coarse timing (for now) + + prx = 1; + nin = Nsamperframe+2*(M+Ncp); + states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx(prx:nin); + prx += nin; + + state = 'searching'; frame_count = 0; + + % main loop ---------------------------------------------------------------- + + for f=1:Nframes + + % insert samples at end of buffer, set to zero if no samples + % available to disable phase estimation on future pilots on last + % frame of simulation + + lnew = min(Nsam-prx,states.nin); + rxbuf_in = zeros(1,states.nin); + + if lnew + rxbuf_in(1:lnew) = rx(prx:prx+lnew-1); + end + prx += states.nin; + + [rx_bits_raw states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); + frame_count++; + + % update sliding windows of rx-ed symbols and symbol amplitudes + + rx_np(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_np(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); + rx_np(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_np; + rx_amp(1:Nsymbolsperinterleavedframe-Nsymbolsperframe) = rx_amp(Nsymbolsperframe+1:Nsymbolsperinterleavedframe); + rx_amp(Nsymbolsperinterleavedframe-Nsymbolsperframe+1:Nsymbolsperinterleavedframe) = arx_amp; + + printf("f: %d state: %s frame_count: %d\n", f, state, frame_count); + + % If looking for sync: check raw BER on frame just received + % against all possible positions in the interleaver frame. + + % iterate state machine ------------------------------------ + + next_state = state; + if strcmp(state,'searching') + + % If looking for sync: check raw BER on frame just received + % against all possible positions in the interleaver frame. + + for ff=1:interleave_frames + st = (ff-1)*Nbitsperframe+1; en = st + Nbitsperframe - 1; + errors = xor(tx_bits_raw(st:en), rx_bits_raw); + Nerrs = sum(errors); + printf(" ff: %d Nerrs: %d\n", ff, Nerrs); + if Nerrs/Nbitsperframe < 0.1 + next_state = 'synced'; + % make sure we get an interleave frame with correct freq offset + % note this introduces a lot of delay, a better idea would be to + % run demod again from interleave_frames back with now-known freq offset + frame_count = ff - interleave_frames; + end + end + end + + if strcmp(state,'synced') + if Nerrs/Nbitsperframe > 0.2 + %next_state = 'searching'; + end + end + + state = next_state; + + if strcmp(state,'searching') + + % still searching? Attempt coarse timing estimate (i.e. detect start of frame) + + st = M+Ncp + Nsamperframe + 1; en = st + 2*Nsamperframe; + [ct_est foff_est] = coarse_sync(states, states.rxbuf(st:en), states.rate_fs_pilot_samples); + if states.verbose + printf(" Nerrs: %d ct_est: %4d foff_est: %3.1f\n", Nerrs, ct_est, foff_est); + end + + % calculate number of samples we need on next buffer to get into sync + + states.nin = Nsamperframe + ct_est - 1; + + % reset modem states + + states.sample_point = states.timing_est = 1; + states.foff_est_hz = foff_est; + end + + if strcmp(state,'synced') + + % we are in sync so log states + + rx_np_log = [rx_np_log arx_np]; + timing_est_log = [timing_est_log states.timing_est]; + delta_t_log = [delta_t_log states.delta_t]; + foff_est_hz_log = [foff_est_hz_log states.foff_est_hz]; + phase_est_pilot_log = [phase_est_pilot_log; aphase_est_pilot_log]; + end + + if strcmp(state,'synced') && (frame_count == interleave_frames) + + % de-interleave QPSK symbols + + arx_np = gp_deinterleave(rx_np); + arx_amp = gp_deinterleave(rx_amp); + + % measure uncoded bit errors per modem frame + + rx_bits_raw = []; + for s=1:Nsymbolsperinterleavedframe + rx_bits_raw = [rx_bits_raw qpsk_demod(rx_np(s))]; + end + for ff=1:interleave_frames + st = (ff-1)*Nbitsperframe+1; en = st+Nbitsperframe-1; + errors = xor(tx_bits_raw(st:en), rx_bits_raw(st:en)); + Nerrs = sum(errors); + if Nerrs/Nbitsperframe < 0.2 + Terrs += Nerrs; + Nerrs_log = [Nerrs_log Nerrs]; + Tbits += Nbitsperframe; + end + end + + % LDPC decode + + rx_bits = []; + for ff=1:interleave_frames + st = (ff-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe/bps - 1; + rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, arx_np(st:en), min(EsNo,30), arx_amp(st:en)); + rx_bits = [rx_bits rx_codeword(1:code_param.data_bits_per_frame)]; + end + + errors_coded = xor(tx_bits, rx_bits); + Nerrs_coded = sum(errors_coded); + if Nerrs/Nbitsperframe < 0.2 + Terrs_coded += Nerrs_coded; + Tbits_coded += code_param.data_bits_per_frame*interleave_frames; + error_positions = [error_positions errors_coded]; + + % measure packet errors based on Codec 2 packet size + + Nvocframes = floor(code_param.data_bits_per_frame*interleave_frames/Nbitspervocframe); + for fv=1:Nvocframes + st = (fv-1)*Nbitspervocframe + 1; + en = st + Nbitspervocframe - 1; + Nvocpacketerrs = sum(xor(tx_bits(st:en), rx_bits(st:en))); + if Nvocpacketerrs + Tpacketerrs++; + end + Tpackets++; + Nerrs_coded_log = [Nerrs_coded_log Nvocpacketerrs]; + end + end + printf(" Nerrs_coded: %d\n", Nerrs_coded); + + frame_count = 0; + end + end + + printf("Coded BER: %5.4f Tbits: %5d Terrs: %5d PER: %5.4f Tpacketerrs: %5d Tpackets: %5d\n", + Terrs_coded/Tbits_coded, Tbits_coded, Terrs_coded, Tpacketerrs/Tpackets, Tpacketerrs, Tpackets); + printf("Raw BER..: %5.4f Tbits: %5d Terrs: %5d\n", Terrs/Tbits, Tbits, Terrs); + + figure(1); clf; + plot(rx_np_log,'+'); + mx = max(abs(rx_np_log)) + axis([-mx mx -mx mx]); + title('Scatter'); + + figure(2); clf; + plot(phase_est_pilot_log(:,2:Nc+1),'g+', 'markersize', 5); + title('Phase est'); + axis([1 length(phase_est_pilot_log) -pi pi]); + + figure(3); clf; + subplot(211) + stem(delta_t_log) + title('delta t'); + subplot(212) + plot(timing_est_log); + title('timing est'); + + figure(4); clf; + plot(foff_est_hz_log) + mx = max(abs(foff_est_hz_log)); + axis([1 max(Nframes,2) -mx mx]); + title('Fine Freq'); + ylabel('Hz') + + figure(5); clf; + subplot(211) + stem(Nerrs_log); + title('Uncoded errrors/modem frame') + axis([1 length(Nerrs_log) 0 Nbitsperframe*rate/2]); + subplot(212) + stem(Nerrs_coded_log); + title('Coded errrors/vocoder frame') + axis([1 length(Nerrs_coded_log) 0 Nbitspervocframe/2]); + + if nargin == 3 + fep = fopen(error_pattern_filename, "wb"); + fwrite(fep, error_positions, "short"); + fclose(fep); + end +endfunction diff --git a/codec2/branches/0.7/octave/ofdm_tx.m b/codec2/branches/0.7/octave/ofdm_tx.m new file mode 100644 index 00000000..e057998f --- /dev/null +++ b/codec2/branches/0.7/octave/ofdm_tx.m @@ -0,0 +1,189 @@ +% ofdm_tx.m +% David Rowe April 2017 +% +% File based ofdm tx. Generate a file of ofdm samples, inclduing +% optional channel simulation. + +#{ + Examples: + + i) 4 frame interleaver, 10 seconds, AWGN channel at Eb/No=3dB + + octave:4> ofdm_tx('awgn_ebno_3dB_700d.raw',4, 10,3); + + ii) 4 frame interleaver, 10 seconds, HF channel at Eb/No=6dB + + ofdm_tx('hf_ebno_6dB_700d.raw', 4, 10, 6, 'hf'); +#} + + +#{ + TODO: + [ ] measure and report raw and coded BER + [ ] maybe 10s worth of frames, sync up to any one automatically + + or start with maybe 10 frames + + measure BER match on each one + [ ] model clipping/PA compression + [ ] sample clock offsets + [ ] compare with same SNR from pathsim + [ ] How to pack arbitrary frames into ofdm frame and codec 2 frames + + integer number of ofdm frames? + + how to sync at other end + +#} + +function ofdm_tx(filename, Nsec, interleave_frames = 1, EbNodB=100, channel='awgn', freq_offset_Hz=0) + ofdm_lib; + ldpc; + gp_interleaver; + + % init modem + + Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8; + states = ofdm_init(bps, Rs, Tcp, Ns, Nc); + ofdm_load_const; + + % Set up LDPC code + + mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray'; + + init_cml('/home/david/Desktop/cml/'); + load HRA_112_112.txt + [code_param framesize rate] = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping); + assert(Nbitsperframe == code_param.code_bits_per_frame); + + % Generate fixed test frame of tx bits and run OFDM modulator + + Nrows = Nsec*Rs; + Nframes = floor((Nrows-1)/Ns); + + % Adjust Nframes so we have an integer number of interleaver frames + % in simulation + + Nframes = interleave_frames*round(Nframes/interleave_frames); + + % OK generate an interleaver frame of codewords from random data bits + + rand('seed', 100); + tx_bits = tx_symbols = []; + for f=1:interleave_frames + atx_bits = round(rand(1,code_param.data_bits_per_frame)); + tx_bits = [tx_bits atx_bits]; + codeword = LdpcEncode(atx_bits, code_param.H_rows, code_param.P_matrix); + for b=1:2:Nbitsperframe + tx_symbols = [tx_symbols qpsk_mod(codeword(b:b+1))]; + end + end + + tx_symbols = gp_interleave(tx_symbols); + + atx = []; + for f=1:interleave_frames + st = (f-1)*Nbitsperframe/bps+1; en = st + Nbitsperframe/bps-1; + atx = [atx ofdm_txframe(states, tx_symbols(st:en))]; + end + + tx = []; + for f=1:Nframes/interleave_frames + tx = [tx atx]; + end + + % not very pretty way to process analog signals with exactly the same channel + % todo: work out a cleaner way + + analog_hack = 0; rx_filter = 0; + if analog_hack || rx_filter + + % simulated SSB tx filter + + [b, a] = cheby1(4, 3, [600, 2600]/(Fs/2)); + h = freqz(b,a,(600:2600)/(Fs/(2*pi))); + filt_gain = (2600-600)/sum(abs(h) .^ 2); % ensures power after filter == before filter + end + + if analog_hack + % load analog signal and convert to complex + + s = load_raw('../raw/ve9qrp_10s.raw')'; + tx = hilbert(s); + + % ssb tx filter + + tx = filter(b,a,sqrt(filt_gain)*tx); + + % normalise power to same as ofdm tx + + nom_tx_pwr = 2/(Ns*(M*M)) + Nc/(M*M); + tx_pwr = var(tx); + tx *= sqrt(nom_tx_pwr/tx_pwr); + end + + Nsam = length(tx); + + % channel simulation + + EsNo = rate * bps * (10 .^ (EbNodB/10)); + variance = 1/(M*EsNo/2); + woffset = 2*pi*freq_offset_Hz/Fs; + + SNRdB = EbNodB + 10*log10(700/3000); + printf("EbNo: %3.1f dB SNR(3k) est: %3.1f dB foff: %3.1fHz ", EbNodB, SNRdB, freq_offset_Hz); + + % set up HF model --------------------------------------------------------------- + + if strcmp(channel, 'hf') + randn('seed',1); + + % some typical values, or replace with user supplied + + dopplerSpreadHz = 1; path_delay_ms = 1; + + path_delay_samples = path_delay_ms*Fs/1000; + printf("Doppler Spread: %3.2f Hz Path Delay: %3.2f ms %d samples\n", dopplerSpreadHz, path_delay_ms, path_delay_samples); + + % generate same fading pattern for every run + + randn('seed',1); + + spread1 = doppler_spread(dopplerSpreadHz, Fs, (Nsec*(M+Ncp)/M)*Fs*1.1); + spread2 = doppler_spread(dopplerSpreadHz, Fs, (Nsec*(M+Ncp)/M)*Fs*1.1); + + % sometimes doppler_spread() doesn't return exactly the number of samples we need + + assert(length(spread1) >= Nsam, "not enough doppler spreading samples"); + assert(length(spread2) >= Nsam, "not enough doppler spreading samples"); + end + + rx = tx; + + if strcmp(channel, 'hf') + rx = tx(1:Nsam) .* spread1(1:Nsam); + rx += [zeros(1,path_delay_samples) tx(1:Nsam-path_delay_samples)] .* spread2(1:Nsam); + + % normalise rx power to same as tx + + nom_rx_pwr = 2/(Ns*(M*M)) + Nc/(M*M); + rx_pwr = var(rx); + rx *= sqrt(nom_rx_pwr/rx_pwr); + end + + rx = rx .* exp(j*woffset*(1:Nsam)); + + % note variance/2 as we are using real() operator, mumble, + % reflection of -ve freq to +ve, mumble, hand wave + + noise = sqrt(variance/2)*0.5*randn(1,Nsam); + rx = real(rx) + noise; + printf("measured SNR: %3.2f dB\n", 10*log10(var(real(tx))/var(noise))+10*log10(4000) - 10*log10(3000)); + + if rx_filter + % ssb rx filter + rx = filter(b,a,sqrt(filt_gain)*rx); + end + + % adjusted by experiment to match rms power of early test signals + + Ascale = 2E5*1.1491; + + frx=fopen(filename,"wb"); fwrite(frx, Ascale*rx, "short"); fclose(frx); +endfunction diff --git a/codec2/branches/0.7/octave/oqpsk.m b/codec2/branches/0.7/octave/oqpsk.m new file mode 100644 index 00000000..49f54cee --- /dev/null +++ b/codec2/branches/0.7/octave/oqpsk.m @@ -0,0 +1,521 @@ +% oqpsk.m +% David Rowe Jan 2017 +% +% Unfiltered OQPSK modem implementation and simulations to test, +% derived from GMSK modem in gmsk.m +% +% Usage: see "choose one of these to run" at the end of this file. + +rand('state',1); +randn('state',1); +graphics_toolkit ("gnuplot"); +format +more off; + +% init modem states + +function oqpsk_states = oqpsk_init(oqpsk_states, Rs) + + % general + + verbose = oqpsk_states.verbose; + oqpsk_states.Fs = 4*Rs; + oqpsk_states.Rs = Rs; + oqpsk_states.bps = 2; % two bit/symbol for QPSK + + M = oqpsk_states.M = oqpsk_states.Fs/oqpsk_states.Rs; + assert(floor(M) == M, "oversampling factor M must be an integer"); + assert(floor(M/2) == M/2, "(oversampling factor M)/2 must be an integer to offset QPSK"); +endfunction + + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +% Unfiltered OQPSK modulator + +function [tx tx_symb] = oqpsk_mod(oqpsk_states, tx_bits) + M = oqpsk_states.M; + bps = oqpsk_states.bps; + nsym = length(tx_bits)/bps; + nsam = nsym*M; + verbose = oqpsk_states.verbose; + + % Map bits to Gray coded QPSK symbols + + tx_symb = zeros(1,nsym); + + for i=1:nsym + tx_symb(i) = qpsk_mod(tx_bits(2*i-1:2*i))*exp(j*pi/4); + end + + % Oversample by M (sample and hold) to create unfiltered QPSK + + tx = zeros(1, nsam); + for i=1:nsym + tx((i-1)*M+1:(i*M)) = tx_symb(i); + end + + % delay Q arm by half of a symbol to make OQPSK + + tx = [real(tx) zeros(1,M/2)] + j*[zeros(1,M/2) imag(tx)]; +endfunction + + +#{ + + Unfiltered OQPSK demodulator function, with (optional) phase and + timing estimation. Adapted from Fig 8 of [1]. See also gmsk.m and + [2]. + + Note demodulator returns phase corrected symbols sampled at ideal + timing instant. These symbols may have a m*pi/2 phase ambiguity due + to properties of phase tracking loop. The caller is responsible for + determining this ambiguity and recovering the actual bits. + + [1] GMSK demodulator in IEEE Trans on Comms, Muroyta et al, 1981, + "GSM Modulation for Digital Radio Telephony". + + [2] GMSK Modem Simulation, http://www.rowetel.com/?p=3824 + +#} + + +function [rx_symb rx_int filt_log dco_log timing_adj Toff] = oqpsk_demod(oqpsk_states, rx) + M = oqpsk_states.M; + Rs = oqpsk_states.Rs; + Fs = oqpsk_states.Fs; + nsam = length(rx); + nsym = floor(nsam/M); + verbose = oqpsk_states.verbose; + + timing_angle_log = zeros(1,length(rx)); + rx_int = zeros(1,length(rx)); + dco_log = filt_log = zeros(1,nsam); + + % Unfiltered PSK - integrate energy in symbols M long in re and im arms + + rx_int = conv(rx,ones(1,M))/M; + + % phase and fine frequency tracking and correction ------------------------ + + if oqpsk_states.phase_est + + % DCO design from "Introduction To Phase-Lock Loop System Modeling", Wen Li + % http://www.ece.ualberta.ca/~ee401/parts/data/PLLIntro.pdf + + eta = 0.707; + wn = 2*pi*10*(Rs/4800); % (Rs/4800) -> found reducing the BW benefical with falling Rs + Ts = 1/Fs; + g1 = 1 - exp(-2*eta*wn*Ts); + g2 = 1 + exp(-2*eta*wn*Ts) - 2*exp(-eta*wn*Ts)*cos(wn*Ts*sqrt(1-eta*eta)); + Gpd = 2/pi; + Gvco = 1; + G1 = g1/(Gpd*Gvco); G2 = g2/(Gpd*Gvco); + %printf("g1: %e g2: %e G1: %e G2: %e\n", g1, g2, G1, G2); + + filt_prev = dco = lower = ph_err_filt = ph_err = 0; + end + + if oqpsk_states.timing_est + % w is the ref sine wave at the timing clock frequency + % tw is the length of the window used to estimate timing + + tw = 200*M; + k = 1; + xr_log = []; xi_log = []; + w_log = []; + timing_clock_phase = 0; + timing_angle = 0; + timing_angle_log = zeros(1,nsam); + end + + % Sample by sample processing loop for timing and phase est. Note + % this operates at sample rate Fs, unlike many PSK modems that + % operate at the symbol rate Rs + + for i=1:nsam + + if oqpsk_states.timing_est + + % update sample timing estimate every tw samples, free wheel + % rest of the time + + if mod(i,tw) == 0 + l = i - tw+1; + xr = abs(real(rx_int(l:l+tw-1))); + xi = abs(imag(rx_int(l:l+tw-1))); + w = exp(j*(l:l+tw-1)*2*pi*Rs/Fs); + X = xr * w'; + timing_clock_phase = timing_angle = angle(X); + k++; + xr_log = [xr_log xr]; + xi_log = [xi_log xi]; + w_log = [w_log w]; + else + timing_clock_phase += (2*pi)/M; + end + timing_angle_log(i) = timing_angle; + end + + if oqpsk_states.phase_est + + % PLL per-sample processing + + rx_int(i) *= exp(-j*dco); + ph_err = sign(real(rx_int(i))*imag(rx_int(i)))*cos(timing_clock_phase); + lower = ph_err*G2 + lower; + filt = ph_err*G1 + lower; + dco_log(i) = dco; + dco = dco + filt; + filt_log(i) = filt; + + end + + end + + % final adjustment of timing output to take into account slowly + % moving estimates due to sample clock offset. Unwrap ensures that + % when timing angle jumps from -pi to pi we move to the next symbol + % and frame sync isn't broken + + timing_adj = timing_angle_log*M/(2*pi); + timing_adj_uw = unwrap(timing_angle_log)*M/(2*pi); + % Toff = floor(2*M+timing_adj); + Toff = floor(timing_adj_uw+0.5); + + % sample integrator output at correct timing instant + + k = 1; + re_syms = im_syms = zeros(1,nsym); + rx_symb = []; + for i=M:M:nsam + if i-Toff(i)+M/2 <= nsam + re_syms(k) = real(rx_int(i-Toff(i))); + im_syms(k) = imag(rx_int(i-Toff(i)+M/2)); + %re_syms(k) = real(rx_int(i)); + %im_syms(k) = imag(rx_int(i)); + rx_symb = [rx_symb re_syms(k) + j*im_syms(k)]; + k++; + end + end + +endfunction + + +% Test modem over a range Eb/No points in an AWGN channel. Can +% simulate a variety of channel impairments and performs ambiguity +% resolution. + +function sim_out = oqpsk_test(sim_in) + bitspertestframe = sim_in.bitspertestframe; + nbits = sim_in.nbits; + EbNodB = sim_in.EbNodB; + verbose = sim_in.verbose; + Rs = 4800; + + oqpsk_states.verbose = verbose; + oqpsk_states.coherent_demod = sim_in.coherent_demod; + oqpsk_states.phase_est = sim_in.phase_est; + oqpsk_states.timing_est = sim_in.timing_est; + oqpsk_states = oqpsk_init(oqpsk_states, Rs); + M = oqpsk_states.M; + Fs = oqpsk_states.Fs; + Rs = oqpsk_states.Rs; + sample_clock_offset_ppm = sim_in.sample_clock_offset_ppm; + + tx_testframe = round(rand(1, bitspertestframe)); + ntestframes = floor(nbits/bitspertestframe); + tx_bits = []; + for i=1:ntestframes + tx_bits = [tx_bits tx_testframe]; + end + + for ne = 1:length(EbNodB) + aEbNodB = EbNodB(ne); + EbNo = 10^(aEbNodB/10); + variance = Fs/(Rs*EbNo*oqpsk_states.bps); + + [tx tx_symb] = oqpsk_mod(oqpsk_states, tx_bits); + if sample_clock_offset_ppm + tx = resample(tx, 1E6, 1E6-sample_clock_offset_ppm); + end + nsam = length(tx); + + phi = sim_in.phase_offset + 2*pi*sim_in.freq_offset*(1:nsam)/M; + + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + st = 1+sim_in.timing_offset; en = length(tx); + rx = tx(st:en).*exp(j*phi(st:en)) + noise(st:en); + + [rx_symb rx_int filt_log dco_log timing_adj Toff] = oqpsk_demod(oqpsk_states, rx); + + % OK so the phase and timing estimators get us close (e.g. a good + % scatter diagram), but no banana just yet. One problem is the + % PLL can lock up on mulitples of pi/2. Combinations of phase + % offsets can confuse the timing estimator. One tricky example is a + % phase offset of pi/2 which swaps I & Q, and with OQPSK (unlike + % MSK and friends) we can't easily tell which is I and which is Q + % after a phase rotation, e.g. could be IQIQIQI or QIQIQIQ + + % So we need to determine the ambiguities: + % a) could be m*pi/2 rotations of phase + % b) could be I and Q swapped by timing est + % c) time alignment of test frame + + nsymb = bitspertestframe/oqpsk_states.bps; + nrx_symb = length(rx_symb); + rx_bits = zeros(1, bitspertestframe); + atx_symb = tx_symb(1:nsymb); + + % Treat I and Q as separate sequences, each with their own unique + % word. In our case the UW is the whole test frame. Correlate rx + % sequence with tx sequence at each possible offset through the + % received symbols to find the test frames. Note we also + % correlate I of tx with Q of rx to trap any IQ swaps. + + % The sign of the I and Q correlation lets us sort out the pi/2 + % phase rotation issue. + + nerrs_tot = 0; nbits_tot = 0; + + max_corr = real(atx_symb) * real(atx_symb)'; + for offset=2:nrx_symb-nsymb+1 + corr_ii(offset) = real(atx_symb) * real(rx_symb(offset:offset+nsymb-1))'/max_corr; + corr_qq(offset) = imag(atx_symb) * imag(rx_symb(offset:offset+nsymb-1))'/max_corr; + corr_iq(offset) = real(atx_symb) * imag(rx_symb(offset:offset+nsymb-1))'/max_corr; + corr_qi(offset) = imag(atx_symb) * real(rx_symb(offset:offset+nsymb-1))'/max_corr; + %printf("offset: %2d ii: % 5f qq: % 5f iq: % 5f qi: % 5f\n", + %offset, corr_ii(offset), corr_qq(offset), corr_iq(offset), corr_qi(offset)); + + if abs(corr_ii(offset)) > 0.8 + + % no IQ swap, or time offset + + i_sign = sign(corr_ii(offset)); + q_sign = sign(corr_qq(offset)); + arx_symb = i_sign*real(rx_symb(offset:offset+nsymb-1)) + j*q_sign*imag(rx_symb(offset:offset+nsymb-1)); + + for i=1:nsymb + rx_bits(2*i-1:2*i) = qpsk_demod(arx_symb(i)*exp(-j*pi/4)); + end + nerrs = sum(xor(tx_testframe, rx_bits)); + if verbose > 2 + printf("offset: %5d swap: %d i_sign: % 2.1f q_sign: % 2.1f nerr: %d\n", + offset, 0, i_sign, q_sign, nerrs); + end + nerrs_tot += nerrs; + nbits_tot += bitspertestframe; + end + + if abs(corr_qi(offset)) > 0.8 + + % IQ swap, I part in Q part of symbol before + + i_sign = sign(corr_iq(offset-1)); + q_sign = sign(corr_qi(offset)); + arx_symb = i_sign*imag(rx_symb(offset-1:offset+nsymb-2)) + j*q_sign*real(rx_symb(offset:offset+nsymb-1)); + + for i=1:nsymb + rx_bits(2*i-1:2*i) = qpsk_demod(arx_symb(i)*exp(-j*pi/4)); + end + nerrs = sum(xor(tx_testframe, rx_bits)); + if verbose > 1 + printf("offset: %5d swap: %d i_sign: % 2.1f q_sign: % 2.1f nerr: %d\n", + offset, 1, i_sign, q_sign, nerrs); + end + nerrs_tot += nerrs; + nbits_tot += bitspertestframe; + end + end + + TERvec(ne) = nerrs_tot; + BERvec(ne) = nerrs_tot/nbits_tot; + + if verbose > 0 + printf("EbNo dB: %3.1f Nbits: %d Nerrs: %d BER: %4.3f BER Theory: %4.3f\n", + aEbNodB, nbits_tot, nerrs_tot, BERvec(ne), 0.5*erfc(sqrt(EbNo))); + end + + if find(sim_in.plots == 1) + figure(1); clf; + subplot(211) + stem(real(tx)) + title('Tx samples'); + ylabel('Inphase'); + subplot(212) + stem(imag(tx)) + ylabel('Quadrature'); + end + + if find(sim_in.plots == 2) + figure(2); clf; + f = fftshift(fft(rx)); + Tx = 20*log10(abs(f)); + plot((1:length(f))*Fs/length(f) - Fs/2, Tx) + grid; + title('OQPSK Demodulator Input Spectrum'); + end + + if find(sim_in.plots == 3) + figure(3); clf; + nplot = min(16, nbits/oqpsk_states.bps); + title('Rx Integrator'); + subplot(211) + stem(real(rx_int(1:nplot*M))) + axis([1 nplot*M -1 1]) + subplot(212) + stem(imag(rx_int(1:nplot*M))) + axis([1 nplot*M -1 1]) + end + + if find(sim_in.plots == 4) + figure(4); clf; + subplot(211); + plot(filt_log); + title('PLL filter') + subplot(212); + plot(dco_log); + title('PLL DCO phase'); + end + + if find(sim_in.plots == 5) + figure(5); clf; + subplot(211) + plot(timing_adj); + title('Timing est'); + subplot(212) + plot(Toff); + title('Timing est unwrap'); + end + + if find(sim_in.plots == 6) + figure(6); clf; + st = floor(0.5*nrx_symb); + plot(rx_symb(st:nrx_symb), '+'); + title('Scatter Diagram'); + axis([-1.5 1.5 -1.5 1.5]) + end + + if find(sim_in.plots == 7) + figure(7); clf; + subplot(211) + plot(corr_ii); + axis([1 length(corr_ii) -1.2 1.2]); + title('corr ii'); + subplot(212) + plot(corr_qi); + axis([1 length(corr_ii) -1.2 1.2]); + title('corr qi'); + end + + if find(sim_in.plots == 8) + figure(8); clf; + subplot(211); + stem(real(arx_symb)); + title('Rx symbols') + subplot(212); + stem(imag(arx_symb)); + end + + if find(sim_in.plots == 9) + figure(9); clf; + subplot(211) + stem(tx_testframe(1:min(20,length(rx_bits)))) + title('Tx Bits') + subplot(212) + stem(rx_bits(1:min(20,length(rx_bits)))) + title('Rx Bits') + end + end + + sim_out.TERvec = TERvec; + sim_out.BERvec = BERvec; + sim_out.Rs = oqpsk_states.Rs; +endfunction + + +function run_oqpsk_single + sim_in.coherent_demod = 1; + sim_in.phase_est = 1; + sim_in.timing_est = 1; + sim_in.bitspertestframe = 100; + sim_in.nbits = 10000; + sim_in.EbNodB = 4; + sim_in.verbose = 1; + sim_in.phase_offset = 3*pi/4; % in radians + sim_in.timing_offset = 4; % in samples 0..M-1 + sim_in.freq_offset = 0.001; % fraction of Symbol Rate + sim_in.plots = [1 2 4 5 6 7]; + sim_in.sample_clock_offset_ppm = 100; + + sim_out = oqpsk_test(sim_in); +endfunction + + +% Generate a bunch of BER versus Eb/No curves for various demods + +function run_oqpsk_curves + sim_in.coherent_demod = 1; + sim_in.EbNodB = 2:8; + sim_in.verbose = 1; + sim_in.phase_est = 1; + sim_in.timing_est = 1; + sim_in.bitspertestframe = 100; + sim_in.nbits = 50000; + sim_in.phase_offset = 3*pi/4; % in radians + sim_in.timing_offset = 4; % in samples 0..M-1 + sim_in.freq_offset = 0.001; % fraction of Symbol Rate + sim_in.plots = []; + sim_in.sample_clock_offset_ppm = 0; + + oqpsk_coh = oqpsk_test(sim_in); + + Rs = oqpsk_coh.Rs; + EbNo = 10 .^ (sim_in.EbNodB/10); + oqpsk_theory.BERvec = 0.5*erfc(sqrt(EbNo)); + + % BER v Eb/No curves + + figure; + clf; + semilogy(sim_in.EbNodB, oqpsk_theory.BERvec,'r+-;OQPSK theory;') + hold on; + semilogy(sim_in.EbNodB, oqpsk_coh.BERvec,'g+-;OQPSK sim;') + hold off; + grid("minor"); + axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") +endfunction + + +% Choose one of these to run ------------------------------------------ + +run_oqpsk_single +%run_oqpsk_curves + diff --git a/codec2/branches/0.7/octave/phase.m b/codec2/branches/0.7/octave/phase.m new file mode 100644 index 00000000..f9735903 --- /dev/null +++ b/codec2/branches/0.7/octave/phase.m @@ -0,0 +1,56 @@ +% phase.m +% David Rowe August 2009 +% experiments with phase for sinusoidal codecs + +function phase(samname, F0, png) + Wo=2*pi*F0/8000; + P=2*pi/Wo; + L = floor(pi/Wo); + Nsam = 16000; + N = 80; + F = Nsam/N; + A = 10000/L; + phi = zeros(1,L); + s = zeros(1,Nsam); + + for m=floor(L/2):L + phi_off(m) = -m*Wo*8; + end + + for f=1:F + phi(1) = phi(1) + Wo*N; + phi(1) = mod(phi(1),2*pi); + + for m=1:L + phi(m) = m*phi(1); + end + + x = zeros(1,N); + for m=1:L + x = x + A*cos(m*Wo*(0:(N-1)) + phi(m)); + endfor + s((f-1)*N+1:f*N) = x; + endfor + + figure(1); + clf; + plot(s(1:250)); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); + + if (nargin == 3) + % small image to fit blog + + __gnuplot_set__ terminal png size 450,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", samname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + endif + +endfunction + diff --git a/codec2/branches/0.7/octave/phase2.m b/codec2/branches/0.7/octave/phase2.m new file mode 100644 index 00000000..5c148f38 --- /dev/null +++ b/codec2/branches/0.7/octave/phase2.m @@ -0,0 +1,57 @@ +% phase2.m +% David Rowe Sep 2009 +% experiments with phase for sinusoidal codecs, looking at phase +% of excitation with real Am samples from hts1 + +function phase2(samname, png) + N = 16000; + + f=43; + model = load("../src/hts1a_phase_model.txt"); + phase = load("../src/hts1a_phase_phase.txt"); + Wo = model(f,1); + P=2*pi/Wo; + L = model(f,2); + A = model(f,3:(L+2)); + phi = phase(f,1:L); + phi = zeros(1,L); + phi(3) = -pi/2; + phi(4) = -pi/4; + phi(5) = pi/2; + + s = zeros(1,N); + + for m=3:5 + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi(m)); + s = s + s_m; + endfor + + figure(1); + clf; + plot(s(1:250)); + + figure(2); + clf; + subplot(211) + plot((1:L)*Wo*4000/pi, 20*log10(A),'+'); + subplot(212) + plot((1:L)*Wo*4000/pi, phi,'+'); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); + + if (nargin == 2) + % small image to fit blog + + __gnuplot_set__ terminal png size 450,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", samname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + endif + +endfunction + diff --git a/codec2/branches/0.7/octave/phasesecord.m b/codec2/branches/0.7/octave/phasesecord.m new file mode 100644 index 00000000..a3cf2516 --- /dev/null +++ b/codec2/branches/0.7/octave/phasesecord.m @@ -0,0 +1,47 @@ +% phasesecord.m +% David Rowe Aug 2012 +% Used to experiment with aproximations of phase of 2nd order systems + +function phasesecord(w,beta) + + a = [1 -2*cos(w)*beta beta*beta]; + b = 1; + + [h w1] = freqz(b,a); + + figure(1) + subplot(211) + plot(abs(h)) + subplot(212) + plot(angle(h)) + + % for beta close to 1, we approximate 3 dB points as 1-beta above + % and below the resonance freq. Note this fails if w=0 as there is a + % double pole. Lets sample the freq response at the 3dB points and + % w: + + ws = [w-(1-beta) w w+(1-beta)]; + [h w1] = freqz(b,a,ws); + + % gain as a fraction of max, should be 3dB. Within 1.3 dB or for w > pi/8, + % gets innacurate near w=0 due to 2nd pole + + printf("mag measured...:"); printf("% 4.3f ", abs(h)/max(abs(h))); + + % measured angle, 45 deg from angle at w + + printf("\nangle measured.: "); printf("% 5.3f ", angle(h)); + + % Our estimate of angle, (pi+w) is phase at resonance, at lower 3dB + % phase is pi/4 ahead, at upper 3B pi/4 behind. -pi/2 is contribution of + % other pole at at -w to phase + + ph_lower = (pi+w) + pi/4 - pi/2; + ph_res =(pi+w) - pi/2; + ph_upper = (pi+w) - pi/4 - pi/2; + ph_ests = [ph_lower ph_res ph_upper]; + ph_ests = ph_ests - 2*pi*(floor(ph_ests/(2*pi)) + 0.5); + printf("\nangle estimated:"); printf("% 5.3f ", ph_ests); + printf("\n"); +endfunction + diff --git a/codec2/branches/0.7/octave/pitch_test.m b/codec2/branches/0.7/octave/pitch_test.m new file mode 100644 index 00000000..3fe0d1ad --- /dev/null +++ b/codec2/branches/0.7/octave/pitch_test.m @@ -0,0 +1,39 @@ +% pitch_test.m +% David Rowe Sep 2009 +% Constructs a sequence to test the pitch estimator + +function pitch_test(samname) + M=320; + F=200; + + fs=fopen(samname,"wb"); + + f0 = 100; + for f=1:200 + Wo=2*pi*f0/8000; + P=2*pi/Wo; + L = floor(pi/Wo); + A = 10000/L; + phi = zeros(1,L); + s = zeros(1,M); + + for m=1:L + s = s + A*cos(m*Wo*(0:(M-1)) + phi(m)); + endfor + + figure(1); + clf; + plot(s); + + fwrite(fs,s,"short"); + + f0 = f0 + 5; + if (f0 > 400) + f0 = 100; + endif + endfor + + fclose(fs); + +endfunction + diff --git a/codec2/branches/0.7/octave/pl.m b/codec2/branches/0.7/octave/pl.m new file mode 100644 index 00000000..0d547882 --- /dev/null +++ b/codec2/branches/0.7/octave/pl.m @@ -0,0 +1,45 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plots a raw speech sample file, you can optionally specify the start and end +% samples and create a large and small PNGs + +function pl(samname1, start_sam, end_sam, pngname) + + fs=fopen(samname1,"rb"); + s=fread(fs,Inf,"short"); + + st = 1; + en = length(s); + if (nargin >= 2) + st = start_sam; + endif + if (nargin >= 3) + en = end_sam; + endif + + figure(1); + clf; + plot(s(st:en)); + axis([1 en-st 1.1*min(s) 1.1*max(s)]); + + if (nargin == 4) + + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + endif + +endfunction diff --git a/codec2/branches/0.7/octave/pl2.m b/codec2/branches/0.7/octave/pl2.m new file mode 100644 index 00000000..c7af10cc --- /dev/null +++ b/codec2/branches/0.7/octave/pl2.m @@ -0,0 +1,44 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +function pl2(samname1, samname2, start_sam, end_sam, offset) + + fs1=fopen(samname1,"rb"); + s1=fread(fs1,Inf,"short"); + fs2=fopen(samname2,"rb"); + s2=fread(fs2,Inf,"short"); + + st1 = st2 = 1; + en1 = en2 = length(s1); + if (nargin >= 3) + st1 = st2 = start_sam; + endif + if (nargin >= 4) + en1 = en2 = end_sam; + endif + + if (nargin == 5) + st2 += offset + en2 += offset + endif + + figure(1); + clf; + subplot(211); + l1 = strcat("r;",samname1,";"); + plot(s1(st1:en1), l1); + axis([1 en1-st1 min(s1(st1:en1)) max(s1(st1:en1))]); + subplot(212); + l2 = strcat("r;",samname2,";"); + plot(s2(st2:en2),l2); + axis([1 en2-st2 min(s1(st2:en2)) max(s1(st2:en2))]); + + figure(2) + plot(s1(st1:en1)-s2(st2:en2)); + + f=fopen("diff.raw","wb"); + d = s1(st1:en1)-s2(st2:en2); + fwrite(f,d,"short"); + +endfunction diff --git a/codec2/branches/0.7/octave/plamp.m b/codec2/branches/0.7/octave/plamp.m new file mode 100644 index 00000000..62b6893a --- /dev/null +++ b/codec2/branches/0.7/octave/plamp.m @@ -0,0 +1,197 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot ampltiude modelling information from dump files. + +function plamp(samname, f, samname2) + + % switch some stuff off to unclutter display + + plot_lsp = 0; + plot_snr = 0; + plot_vsnr = 0; + plot_sw = 0; + plot_pw = 0; + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + sw__name = strcat(samname,"_sw_.txt"); + if (file_in_path(".",sw__name)) + Sw_ = load(sw__name); + endif + + ew_name = strcat(samname,"_ew.txt"); + if (file_in_path(".",ew_name)) + Ew = load(ew_name); + endif + + rk_name = strcat(samname,"_rk.txt"); + if (file_in_path(".",rk_name)) + Rk = load(rk_name); + endif + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + modelq_name = strcat(samname,"_qmodel.txt"); + if (file_in_path(".",modelq_name)) + modelq = load(modelq_name); + endif + + pw_name = strcat(samname,"_pw.txt"); + if (file_in_path(".",pw_name)) + Pw = load(pw_name); + endif + + lsp_name = strcat(samname,"_lsp.txt"); + if (file_in_path(".",lsp_name)) + lsp = load(lsp_name); + endif + + phase_name = strcat(samname,"_phase.txt"); + if (file_in_path(".",phase_name)) + phase = load(phase_name); + endif + + phase_name_ = strcat(samname,"_phase_.txt"); + if (file_in_path(".",phase_name_)) + phase_ = load(phase_name_); + endif + + snr_name = strcat(samname,"_snr.txt"); + if (file_in_path(".",snr_name)) + snr = load(snr_name); + endif + + % optional second file, for exploring post filter + + model2q_name = " "; + if nargin == 3 + model2q_name = strcat(samname2,"_qmodel.txt"); + if file_in_path(".",modelq_name) + model2q = load(model2q_name); + end + end + + Ew_on = 1; + k = ' '; + do + figure(1); + clf; +% s = [ Sn(2*(f-2)-1,:) Sn(2*(f-2),:) ]; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + size(s); + plot(s); + axis([1 length(s) -20000 20000]); + + figure(2); + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Am),";Am;r"); + axis([1 4000 -10 80]); + hold on; + if plot_sw + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + end + + if (file_in_path(".",modelq_name)) + Amq = modelq(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Amq),";Amq;g" ); + if (file_in_path(".",pw_name) && plot_pw) + plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;c"); + endif + signal = Am * Am'; + noise = (Am-Amq) * (Am-Amq)'; + snr1 = 10*log10(signal/noise); + Am_err_label = sprintf(";Am error SNR %4.2f dB;m",snr1); + plot((1:L)*Wo*4000/pi, 20*log10(Amq) - 20*log10(Am), Am_err_label); + endif + + if file_in_path(".",model2q_name) + Amq2 = model2q(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Amq2),";Amq2;m" ); + end + + if (file_in_path(".",snr_name) && plot_vsnr) + snr_label = sprintf(";Voicing SNR %4.2f dB;",snr(f)); + plot(1,1,snr_label); + endif + + % phase model - determine SNR and error spectrum for phase model 1 + + if (file_in_path(".",phase_name_)) + orig = Am.*exp(j*phase(f,1:L)); + synth = Am.*exp(j*phase_(f,1:L)); + signal = orig * orig'; + noise = (orig-synth) * (orig-synth)'; + snr_phase = 10*log10(signal/noise); + + %phase_err_label = sprintf(";phase_err SNR %4.2f dB;",snr_phase); + %plot((1:L)*Wo*4000/pi, 20*log10(orig-synth), phase_err_label); + endif + + if (file_in_path(".",lsp_name) && plot_lsp) + for l=1:10 + plot([lsp(f,l)*4000/pi lsp(f,l)*4000/pi], [60 80], 'r'); + endfor + endif + + hold off; + + %if (file_in_path(".",phase_name)) + %figure(3); + %plot((1:L)*Wo*4000/pi, phase(f,1:L), ";phase;"); + %axis; + %if (file_in_path(".",phase_name_)) + %hold on; + %plot((1:L)*Wo*4000/pi, phase_(f,1:L), ";phase_;"); + %hold off; + %endif + %figure(2); + %endif + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit e-toggle Ew", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + if (k == 'e') + if (Ew_on == 1) + Ew_on = 0; + else + Ew_on = 1; + endif + endif + + % optional print to PNG + + if (k == 'p') + figure(1); + pngname = sprintf("%s_%d_sn.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sn_large.png",samname,f); + print(pngname, '-dpng', "-S800,600") + + figure(2); + pngname = sprintf("%s_%d_sw.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sw_large.png",samname,f); + print(pngname, '-dpng', "-S1200,800") + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/plinterp.m b/codec2/branches/0.7/octave/plinterp.m new file mode 100644 index 00000000..794a0853 --- /dev/null +++ b/codec2/branches/0.7/octave/plinterp.m @@ -0,0 +1,11 @@ +load ../unittest/tinterp_prev.txt; +load ../unittest/tinterp_interp.txt; +load ../unittest/tinterp_next.txt; + +clf; +plot(tinterp_prev(:,1), 20.0*log10(tinterp_prev(:,2)),";prev;") +hold on; +plot(tinterp_interp(:,1), 20.0*log10(tinterp_interp(:,2)),'g+-;interp;') +plot(tinterp_next(:,1), 20.0*log10(tinterp_next(:,2)),'ro-;next;') +hold off; +axis([0 pi 0 80]) diff --git a/codec2/branches/0.7/octave/pllpcpf.m b/codec2/branches/0.7/octave/pllpcpf.m new file mode 100644 index 00000000..924e045a --- /dev/null +++ b/codec2/branches/0.7/octave/pllpcpf.m @@ -0,0 +1,150 @@ +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot amplitude modelling information from dump files to test and develop +% LPC post filter. + +function pllpcpf(samname, f) + + % switch some stuff off to unclutter display + + plot_Am = 0; + plot_Amq = 0; + plot_err = 0; + plot_lsp = 0; + plot_snr = 0; + plot_vsnr = 0; + plot_sw = 0; + plot_pw = 1; + plot_pwb = 1; + plot_rw = 1; + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + sw__name = strcat(samname,"_sw_.txt"); + if (file_in_path(".",sw__name)) + Sw_ = load(sw__name); + endif + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + modelq_name = strcat(samname,"_qmodel.txt"); + if (file_in_path(".",modelq_name)) + modelq = load(modelq_name); + endif + + % Pw (LPC synth filter spectrum) before post filter + + pwb_name = strcat(samname,"_pwb.txt"); + if (file_in_path(".",pwb_name)) + Pwb = load(pwb_name); + endif + + % Rw (Post filter spectrum) + + rw_name = strcat(samname,"_rw.txt"); + if (file_in_path(".",rw_name)) + Rw = load(rw_name); + endif + + % Pw (LPC synth filter spectrum) after post filter + + pw_name = strcat(samname,"_pw.txt"); + if (file_in_path(".",pw_name)) + Pw = load(pw_name); + endif + + + Ew_on = 1; + k = ' '; + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + size(s); + plot(s); + axis([1 length(s) -20000 20000]); + + figure(2); + clf; + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + if plot_Am + plot((1:L)*Wo*4000/pi, 20*log10(Am),";Am;r"); + end + axis([1 4000 -10 80]); + hold on; + if plot_sw + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + end + + if (file_in_path(".",modelq_name)) + + Amq = modelq(f,3:(L+2)); + if plot_Amq + plot((1:L)*Wo*4000/pi, 20*log10(Amq),";Amq;g" ); + end + + if (file_in_path(".",pwb_name) && plot_pwb) + plot((0:255)*4000/256, 10*log10(Pwb(f,:)),";Pwb;r"); + endif + + if (file_in_path(".",rw_name) && plot_rw) + plot((0:255)*4000/256, 10*log10(Rw(f,:)),";Rw;b"); + endif + + if (file_in_path(".",pw_name) && plot_pw) + plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;g."); + endif + + signal = Am * Am'; + noise = (Am-Amq) * (Am-Amq)'; + snr1 = 10*log10(signal/noise); + Am_err_label = sprintf(";Am error SNR %4.2f dB;m",snr1); + if plot_err + plot((1:L)*Wo*4000/pi, 20*log10(Amq) - 20*log10(Am), Am_err_label); + end + endif + + + hold off; + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + figure(1); + pngname = sprintf("%s_%d_sn.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sn_large.png",samname,f); + print(pngname, '-dpng', "-S800,600") + + figure(2); + pngname = sprintf("%s_%d_sw.png",samname,f); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_%d_sw_large.png",samname,f); + print(pngname, '-dpng', "-S1200,800") + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/pllsp.m b/codec2/branches/0.7/octave/pllsp.m new file mode 100644 index 00000000..0606d3ca --- /dev/null +++ b/codec2/branches/0.7/octave/pllsp.m @@ -0,0 +1,46 @@ +% Copyright David Rowe 2010 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plots a bunch of information related to LSP quantisation: +% - speech file +% - LSPs before and after quantisation +% - SNR for each frame +% +% Note: there is a 160 sample (two frame delay) from the when a sample +% enters the input buffer until it is at the centre of the analysis window + +function pllsp(rawfile, + dumpfile_prefix_lpc_only, + dumpfile_prefix_lsp, + start_f, end_f) + + fs=fopen(rawfile,"rb"); + s=fread(fs,Inf,"short"); + + lpc_snr_name = strcat(dumpfile_prefix_lpc_only,"_lpc_snr.txt"); + lpc10_snr = load(lpc_snr_name); + lpc_snr_name = strcat(dumpfile_prefix_lsp,"_lpc_snr.txt"); + lsp_snr = load(lpc_snr_name); + + lsp_name = strcat(dumpfile_prefix_lsp,"_lsp.txt"); + lsps = load(lsp_name); + [m,n]=size(lsps); + lsp = lsps(1:2:m,:); + lsp_ = lsps(2:2:m,:); + + figure(1); + clf; + subplot(211); + sp = s((start_f-2)*80:(end_f-2)*80); + plot(sp); + + subplot(212); + plot(lpc10_snr((start_f+1):end_f)-lsp_snr((start_f+1):end_f)); + + figure(2); + plot((4000/pi)*lsp((start_f+1):end_f,:)); + hold on; + plot((4000/pi)*lsp_((start_f+1):end_f,:),'+-'); + hold off; +endfunction diff --git a/codec2/branches/0.7/octave/pllspdt.m b/codec2/branches/0.7/octave/pllspdt.m new file mode 100644 index 00000000..c711aa46 --- /dev/null +++ b/codec2/branches/0.7/octave/pllspdt.m @@ -0,0 +1,27 @@ +% pllspdt.m +% Copyright David Rowe 2010 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Test script to plot differences in LSps between frames + +function pllspdt(rawfile,dumpfile_prefix_lsp,lspn, start_f, end_f) + + fs=fopen(rawfile,"rb"); + s=fread(fs,Inf,"short"); + + lsp_name = strcat(dumpfile_prefix_lsp,"_lsp.txt"); + lsps = load(lsp_name); + [m,n]=size(lsps); + lsp = lsps(1:2:m,:); + lsp_ = lsps(2:2:m,:); + lspdt = lsp(2:m/2,:) - lsp(1:m/2-1,:); + + figure(1); + clf; + sp = s((start_f-2)*80:(end_f-2)*80); + plot(sp); + + figure(2); + plot((4000/pi)*lspdt((start_f+1):end_f,lspn)); +endfunction diff --git a/codec2/branches/0.7/octave/plnlp.m b/codec2/branches/0.7/octave/plnlp.m new file mode 100644 index 00000000..01b49311 --- /dev/null +++ b/codec2/branches/0.7/octave/plnlp.m @@ -0,0 +1,134 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot NLP states from dump files. + +function plnlp(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + fw_name = strcat(samname,"_fw.txt"); + if (file_in_path(".",fw_name)) + fw = load(fw_name); + endif + + e_name = strcat(samname,"_e.txt"); + if (file_in_path(".",e_name)) + e = load(e_name); + endif + + p_name = strcat(samname,".p"); + if (file_in_path(".",p_name)) + p = load(p_name); + endif + + sq_name = strcat(samname,"_sq.txt"); + if (file_in_path(".",sq_name)) + sq = load(sq_name); + endif + + dec_name = strcat(samname,"_dec.txt"); + if (file_in_path(".",dec_name)) + dec = load(dec_name); + endif + + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s, ";Sn;"); + grid + axis([1 length(s) -20000 20000]); + + figure(2); + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + grid + axis([1 4000 -10 80]); + hold on; + + f0 = 8000/p(f); + Wo = 2*pi/p(f); + L = floor(pi/Wo); + f0_label = sprintf("b;P=%3.1f F0=%3.0f;",p(f),f0); + for m=1:L-1 + plot([ m*Wo*4000/pi m*Wo*4000/pi], [10 60], 'b'); + endfor + plot([ L*Wo*4000/pi L*Wo*4000/pi], [10 60], f0_label); + + hold off; + + if (file_in_path(".",fw_name)) + figure(3); + if (file_in_path(".",e_name)) + subplot(211); + endif + plot((0:255)*800/256, fw(f,:)/max(fw(f,:)), ";Fw;"); + axis([1 400 0 1]); + if (file_in_path(".",e_name)) + subplot(212); + e_concat = [ e(2*f-1,:) e(2*f,:) ]; + plot(e_concat(1:400)/max(e_concat(1:400)), "+;MBE E(f);"); + axis([1 400 0 1]); + endif + endif + + if (file_in_path(".",sq_name)) + figure(4); + sq_concat = [ sq(2*f-1,:) sq(2*f,:) ]; + axis + plot(sq_concat, ";sq;"); + endif + + if (file_in_path(".",dec_name)) + figure(5); + plot(dec(f,:), ";dec;"); + endif + + figure(2); + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + + pngname = sprintf("%s_%d",samname,f); + + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/plot_specgram.m b/codec2/branches/0.7/octave/plot_specgram.m new file mode 100644 index 00000000..480253eb --- /dev/null +++ b/codec2/branches/0.7/octave/plot_specgram.m @@ -0,0 +1,30 @@ +% plot_specgram.m +% David Rowe May 2017 +% +% As the name suggests..... + + +function S = plot_specgram(x) + + % set step size so we end up with an aray of pixels that is square. Otherwise + % imagesc will only use a ribbon on the figure. + + Fs = 8000; + l = length(x); + + Nfft = 512; Nfft2 = Nfft/2; window = 512; nstep = window/2; + nsamples = floor(l/nstep) - 1; + S = zeros(nsamples,Nfft); + h = hanning(Nfft); + for i=1:nsamples + st = (i-1)*nstep+1; en = st+window-1; + %printf("i: %d st: %d en: %d l: %d\n", i, st, en, l); + S(i,:) = 20*log10(abs(fft(x(st:en).*h'))); + end + mx = ceil(max(max(S))/10)*10; + S = max(S,mx-30); + mesh((1:Nfft2)*4000/Nfft2, (1:nsamples)*nstep, S(:,1:Nfft2)); + view(90,-90); + %xlabel('Frequency (Hz)'); + %ylabel('Sample'); +en diff --git a/codec2/branches/0.7/octave/plphase.m b/codec2/branches/0.7/octave/plphase.m new file mode 100644 index 00000000..c12422ea --- /dev/null +++ b/codec2/branches/0.7/octave/plphase.m @@ -0,0 +1,198 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot phase modelling information from dump files. + +function plphase(samname, f) + + sn_name = strcat(samname,"_sn.txt"); + Sn = load(sn_name); + + sw_name = strcat(samname,"_sw.txt"); + Sw = load(sw_name); + + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + sw__name = strcat(samname,"_sw_.txt"); + if (file_in_path(".",sw__name)) + Sw_ = load(sw__name); + endif + + pw_name = strcat(samname,"_pw.txt"); + if (file_in_path(".",pw_name)) + Pw = load(pw_name); + endif + + ak_name = strcat(samname,"_ak.txt"); + if (file_in_path(".",ak_name)) + ak = load(ak_name); + endif + + phase_name = strcat(samname,"_phase.txt"); + if (file_in_path(".",phase_name)) + phase = load(phase_name); + endif + + phase_name_ = strcat(samname,"_phase_.txt"); + if (file_in_path(".",phase_name_)) + phase_ = load(phase_name_); + endif + + snr_name = strcat(samname,"_snr.txt"); + if (file_in_path(".",snr_name)) + snr = load(snr_name); + endif + + sn_name_ = strcat(samname,".raw"); + if (file_in_path(".",sn_name_)) + fs_ = fopen(sn_name_,"rb"); + sn_ = fread(fs_,Inf,"short"); + endif + + k = ' '; + do + figure(1); + clf; + s = [ Sn(2*f-1,:) Sn(2*f,:) ]; + plot(s); + grid; + axis([1 length(s) -20000 20000]); + if (k == 'p') + pngname = sprintf("%s_%d_sn",samname,f); + png(pngname); + endif + + figure(2); + Wo = model(f,1); + L = model(f,2); + Am = model(f,3:(L+2)); + plot((1:L)*Wo*4000/pi, 20*log10(Am),"r;Am;"); + axis([1 4000 -10 80]); + hold on; + plot((0:255)*4000/256, Sw(f,:),";Sw;"); + grid; + + if (file_in_path(".",sw__name)) + plot((0:255)*4000/256, Sw_(f,:),"g;Sw_;"); + endif + + if (file_in_path(".",pw_name)) + plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;"); + endif + + if (file_in_path(".",snr_name)) + snr_label = sprintf(";phase SNR %4.2f dB;",snr(f)); + plot(1,1,snr_label); + endif + + % phase model - determine SNR and error spectrum for phase model 1 + + if (file_in_path(".",phase_name_)) + orig = Am.*exp(j*phase(f,1:L)); + synth = Am.*exp(j*phase_(f,1:L)); + signal = orig * orig'; + noise = (orig-synth) * (orig-synth)'; + snr_phase = 10*log10(signal/noise); + + phase_err_label = sprintf("g;phase_err SNR %4.2f dB;",snr_phase); + plot((1:L)*Wo*4000/pi, 20*log10(orig-synth), phase_err_label); + endif + + hold off; + if (k == 'p') + pngname = sprintf("%s_%d_sw",samname,f); + png(pngname); + endif + + if (file_in_path(".",phase_name)) + figure(3); + plot((1:L)*Wo*4000/pi, phase(f,1:L)*180/pi, "-o;phase;"); + axis; + if (file_in_path(".", phase_name_)) + hold on; + plot((1:L)*Wo*4000/pi, phase_(f,1:L)*180/pi, "g;phase after;"); + grid + hold off; + endif + if (k == 'p') + pngname = sprintf("%s_%d_phase",samname,f); + png(pngname); + endif + endif + + % synthesised speech + + if (file_in_path(".",sn_name_)) + figure(4); + s_ = sn_((f-3)*80+1:(f+1)*80); + plot(s_); + axis([1 length(s_) -20000 20000]); + if (k == 'p') + pngname = sprintf("%s_%d_sn_",samname,f) + png(pngname); + endif + endif + + if (file_in_path(".",ak_name)) + figure(5); + axis; + akw = ak(f,:); + weight = 1.0 .^ (0:length(akw)-1); + akw = akw .* weight; + H = 1./fft(akw,8000); + subplot(211); + plot(20*log10(abs(H(1:4000))),";LPC mag spec;"); + grid; + subplot(212); + plot(angle(H(1:4000))*180/pi,";LPC phase spec;"); + grid; + if (k == 'p') + % stops multimode errors from gnuplot, I know not why... + figure(2); + figure(5); + + pngname = sprintf("%s_%d_lpc",samname,f); + png(pngname); + endif + endif + + + % autocorrelation function to research voicing est + + %M = length(s); + %sw = s .* hanning(M)'; + %for k=0:159 + % R(k+1) = sw(1:320-k) * sw(1+k:320)'; + %endfor + %figure(4); + %R_label = sprintf(";R(k) %3.2f;",max(R(20:159))/R(1)); + %plot(R/R(1),R_label); + %grid + + figure(2); + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + pngname = sprintf("%s_%d",samname,f); + png(pngname); + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/plpitch.m b/codec2/branches/0.7/octave/plpitch.m new file mode 100644 index 00000000..69ad5338 --- /dev/null +++ b/codec2/branches/0.7/octave/plpitch.m @@ -0,0 +1,36 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% plpitch.m +% Plots two pitch tracks on top of each other, used for comparing pitch +% estimators + +function plpitch(pitch1_name, pitch2_name, start_fr, end_fr) + + pitch1 = load(pitch1_name); + pitch2 = load(pitch2_name); + + st = 1; + en = length(pitch1); + if (nargin >= 3) + st = start_fr; + endif + if (nargin >= 4) + en = end_fr; + endif + + figure(1); + clf; + l1 = strcat("r;",pitch1_name,";") + l1 + st + en + plot(pitch1(st:en), l1); + axis([1 en-st 20 160]); + l2 = strcat("g;",pitch2_name,";"); + hold on; + plot(pitch2(st:en),l2); + hold off; +endfunction + diff --git a/codec2/branches/0.7/octave/plppe.m b/codec2/branches/0.7/octave/plppe.m new file mode 100644 index 00000000..cbc5b562 --- /dev/null +++ b/codec2/branches/0.7/octave/plppe.m @@ -0,0 +1,65 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot two sparse phase prediction error text files. +% Generate data from print_pred_error, print_pred_error_sparse_wo_correction1 etc + +function plppe(ppe1_file, ppe2_file, f) + + ppe1 = load(ppe1_file); + ppe2 = load(ppe2_file); + + std1 = std(nonzeros(ppe1(:,40:80))); + std2 = std(nonzeros(ppe2(:,40:80))); + + printf("std dev for %s is %4.3f\n", ppe1_file, std1); + printf("std dev for %s is %4.3f\n", ppe2_file, std2); + + figure(1); + clf; + subplot(211) + hist(nonzeros(ppe1(:,40:80)),20); + subplot(212) + hist(nonzeros(ppe2(:,40:80)),20); + + k = ' '; + do + figure(2); + clf; + subplot(211) + L = length(nonzeros(ppe1(f,:))); + x = (1:L)*4000/L; + std1 = std(nonzeros(ppe1(f,:))); + legend = sprintf(";std dev %4.3f;", std1); + plot(x, nonzeros(ppe1(f,:)),legend); + axis([0 4000 -pi pi]); + subplot(212) + std2 = std(nonzeros(ppe2(f,:))); + legend = sprintf(";std dev %4.3f;", std2); + plot(x, nonzeros(ppe2(f,:)),legend); + axis([0 4000 -pi pi]); + + % interactive menu + + printf("\rframe: %d menu: n-next b-back p-png q-quit ", f); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + % optional print to PNG + + if (k == 'p') + pngname = sprintf("%s_%d",samname,f); + png(pngname); + endif + + until (k == 'q') + printf("\n"); + +endfunction diff --git a/codec2/branches/0.7/octave/plsub.m b/codec2/branches/0.7/octave/plsub.m new file mode 100644 index 00000000..6e2bc1ea --- /dev/null +++ b/codec2/branches/0.7/octave/plsub.m @@ -0,0 +1,35 @@ +% Copyright David Rowe 2010 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% plots the difference of two files + +function plsub(samname1, samname2, start_sam, end_sam, pngname) + + fs1=fopen(samname1,"rb"); + s1=fread(fs1,Inf,"short"); + fs2=fopen(samname2,"rb"); + s2=fread(fs2,Inf,"short"); + + st = 1; + en = length(s1); + if (nargin >= 3) + st = start_sam; + endif + if (nargin >= 4) + en = end_sam; + endif + + figure(1); + clf; + l1 = strcat("r;",samname1,";"); + plot(s1(st:en) - s2(st:en), l1); + %axis([1 en-st min(s1(st:en)) max(s1(st:en))]); + + if (nargin == 5) + pngname = sprintf("%s.png",pngname); + print(pngname, '-dpng', "-S500,500") + pngname = sprintf("%s_large.png",pngname); + print(pngname, '-dpng', "-S800,600") + endif + +endfunction diff --git a/codec2/branches/0.7/octave/plvoicing.m b/codec2/branches/0.7/octave/plvoicing.m new file mode 100644 index 00000000..a5317476 --- /dev/null +++ b/codec2/branches/0.7/octave/plvoicing.m @@ -0,0 +1,89 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot voicing information from sample and dump files. +% +% samfilename is the raw source file, e.g. "../raw/hts1a.raw" +% samname is the dumpfile prefix, e.g. "../src/hts1a" +% +% There is a 160 sample (two frame delay) from the when a sample +% enters the input buffer until it is at the centre of the analysis window + +function plvoicing(samfilename, samname, start_f, end_f, pngname) + + fs=fopen(samfilename,"rb"); + s=fread(fs,Inf,"short"); + + snr_name = strcat(samname,"_snr.txt"); + snr = load(snr_name); + model_name = strcat(samname,"_model.txt"); + model = load(model_name); + + Wo = model((start_f+1):end_f,1); + F0 = Wo*4000/pi; + dF0 = F0(1:length(Wo)-1) - F0(2:length(Wo)); + + % work out LP and HP energy + + for f=(start_f+1):end_f + L = model(f,2); + Am = model(f,3:(L+2)); + L2 = floor(L/2); + elow = Am(1:L2) * Am(1:L2)'; + ehigh = Am(L2:L) * Am(L2:L)'; + erat(f-(start_f+1)+1) = 10*log10(elow/ehigh); + endfor + + figure(1); + clf; + sp = s((start_f-2)*80:(end_f-2)*80); + plot(sp); + hold on; + vhigh = snr((start_f+1):end_f) > 7; + vlow = snr((start_f+1):end_f) > 4; + + % test correction based on erat + + vlowadj = vlow; + + for f=1:length(erat)-1 + if (vlow(f) == 0) + if (erat(f) > 10) + vlowadj(f) = 1; + endif + endif + if (vlow(f) == 1) + if (erat(f) < -10) + vlowadj(f) = 0; + endif + if (abs(dF0(f)) > 15) + vlowadj(f) = 0; + endif + endif + endfor + + x = 1:(end_f-start_f); + plot(x*80,snr((start_f+1):end_f)*1000,';SNRdB x 1000;g+'); + plot(x*80,-8000 + vhigh*2000,';7dB thresh;g'); + plot(x*80,-11000 + vlowadj*2000,';vlow with corr;g'); + plot(x*80,erat*1000,';elow/ehigh in dB;r'); + plot(x*80,-14000 + vlow*2000,';4dB thresh;r'); + hold off; + grid + if (nargin == 5) + print(pngname, "-dpng", "-S500,500") + endif + + figure(2) + Wo = model((start_f+1):end_f,1); + F0 = Wo*4000/pi; + dF0 = F0(1:length(Wo)-1) - F0(2:length(Wo)); + %plot(dF0,'+--') + %hold on; + %plot([ 1 length(dF0) ], [10 10] ,'r') + %plot([ 1 length(dF0) ], [-10 -10] ,'r') + %axis([1 length(dF0) -50 50]) + %hold off; + plot(F0,'+--') +endfunction diff --git a/codec2/branches/0.7/octave/png.m b/codec2/branches/0.7/octave/png.m new file mode 100644 index 00000000..09a79968 --- /dev/null +++ b/codec2/branches/0.7/octave/png.m @@ -0,0 +1,25 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Replot current plot as a png, generates small and large versions + +function png(pngname) + % small image + + __gnuplot_set__ terminal png size 420,300 + ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname); + eval(ss) + replot; + + % larger image + + __gnuplot_set__ terminal png size 800,600 + ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname); + eval(ss) + replot; + + % for some reason I need this to stop large plot getting wiped + __gnuplot_set__ output "/dev/null" + +endfunction diff --git a/codec2/branches/0.7/octave/postfilter.m b/codec2/branches/0.7/octave/postfilter.m new file mode 100644 index 00000000..84f7dfc7 --- /dev/null +++ b/codec2/branches/0.7/octave/postfilter.m @@ -0,0 +1,24 @@ +% Copyright David Rowe 2009 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% +% Plot postfilter doing its thing + +function postfilter(samname) + p = load(samname); + figure(1); + plot(p(:,1),";energy;"); + hold on; + plot(p(:,2),";bg_est;"); + hold off; + grid; + pngname=sprintf("%s_postfilter_1", samname); + png(pngname); + + figure(2); + plot(p(:,3),";% unvoiced;"); + grid; + pngname=sprintf("%s_postfilter_2", samname); + png(pngname); +endfunction + diff --git a/codec2/branches/0.7/octave/pulse.m b/codec2/branches/0.7/octave/pulse.m new file mode 100644 index 00000000..223389e7 --- /dev/null +++ b/codec2/branches/0.7/octave/pulse.m @@ -0,0 +1,37 @@ +% pulse.m +% David Rowe August 2009 +% +% Experiments with human pulse perception for sinusoidal codecs + +function pulse(samname) + + A = 1000; + K = 16000; + N = 80; + frames = K/N; + s = zeros(1,K); + + for f=1:frames + % lets try placing np random pulses in every frame + + P = 20 + (160-20)*rand(1,1); + Wo = 2*pi/P; + L = floor(pi/Wo); + sf = zeros(1,N); + for m=1:L/2:L + pos = floor(rand(1,1)*N)+1; + %pos = 50; + for l=m:m+L/2-1 + sf = sf + A*cos(l*Wo*((f-1)*N+1:f*N) - pos*l*Wo); + endfor + endfor + s((f-1)*N+1:f*N) = sf; + endfor + + plot(s(1:250)); + + fs=fopen(samname,"wb"); + fwrite(fs,s,"short"); + fclose(fs); +endfunction + diff --git a/codec2/branches/0.7/octave/qpsk.m b/codec2/branches/0.7/octave/qpsk.m new file mode 100644 index 00000000..b502e164 --- /dev/null +++ b/codec2/branches/0.7/octave/qpsk.m @@ -0,0 +1,140 @@ +% qpsk.m +% +% David Rowe Sep 2015 +% +% Octave functions to implement a QPSK modem + +1; + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +% Inserts pilot symbols a frame of symbols. The pilot symbols are +% spread evenly throughout the input frame. + +function frameout = insert_pilots(framein, pilots, Npilotstep) + + lpilots = length(pilots); + lframein = length(framein); + frameout = zeros(1, lframein + lpilots); + + pin = 1; pout = 1; ppilots = 1; + while (lpilots) + %printf("pin %d pout %d ppilots %d lpilots %d\n", pin, pout, ppilots, lpilots); + frameout(pout:pout+Npilotstep-1) = framein(pin:pin+Npilotstep-1); + pin += Npilotstep; + pout += Npilotstep; + frameout(pout:pout) = pilots(ppilots); + ppilots++; + pout++; + lpilots--; + end +endfunction + + +% Removes the pilots symbols from a frame of symbols. + +function frameout = remove_pilots(framein, pilots, Npilotstep) + + frameout = []; + lpilots = length(pilots); + + pin = 1; pout = 1; + while (lpilots) + %printf("pin %d pout %d lpilots %d ", pin, pout, lpilots); + %printf("pin+spacing-1 %d lvd %d lframein: %d\n", pin+spacing-1, lvd, length(framein)); + frameout(pout:pout+Npilotstep-1) = framein(pin:pin+Npilotstep-1); + pin += Npilotstep+1; + pout += Npilotstep; + lpilots--; + end + +endfunction + + +% Estimate and correct phase offset using a window of Np pilots around +% current symbol + +function symbpilot_rx = correct_phase_offset(aqpsk, symbpilot_rx) + rx_pilot_buf = aqpsk.rx_pilot_buf; + Npilotstep = aqpsk.Npilotstep; + Nsymb = aqpsk.Nsymb; + + for ns=1:Npilotstep+1:Nsymb + + % update buffer of recent pilots, note we need past ones + + rx_pilot_buf(1) = rx_pilot_buf(2); + next_pilot_index = ceil(ns/(Npilotstep+1))*(Npilotstep+1); + rx_pilot_buf(2) = symbpilot_rx(next_pilot_index); + + % average pilot symbols to get estimate of phase + + phase_est = angle(sum(rx_pilot_buf)); + + %printf("next_pilot_index: %d phase_est: %f\n", next_pilot_index, phase_est); + + % now correct the phase of each symbol + + for s=ns:ns+Npilotstep + symbpilot_rx(s) *= exp(-j*phase_est); + end + end + + aqpsk.rx_pilot_buf = rx_pilot_buf; +endfunction + + +% builds up a sparse QPSK modulated version version of the UW for use +% in UW sync at the rx + +function mod_uw = build_mod_uw(uw, spacing) + luw = length(uw); + + mod_uw = []; + + pout = 1; puw = 1; + while (luw) + %printf("pin %d pout %d puw %d luw %d\n", pin, pout, puw, luw); + pout += spacing/2; + mod_uw(pout) = qpsk_mod(uw(puw:puw+1)); + puw += 2; + pout += 1; + luw -= 2; + end +endfunction + + +% Uses the UW to determine when we have a full codeword ready for decoding + +function [found_uw corr] = look_for_uw(mem_rx_symbols, mod_uw) + sparse_mem_rx_symbols = mem_rx_symbols(find(mod_uw)); + + % correlate with ref UW + + num = (mem_rx_symbols * mod_uw') .^ 2; + den = (sparse_mem_rx_symbols * sparse_mem_rx_symbols') * (mod_uw * mod_uw'); + + corr = abs(num/(den+1E-6)); + found_uw = corr > 0.8; +endfunction + diff --git a/codec2/branches/0.7/octave/rfdesign.m b/codec2/branches/0.7/octave/rfdesign.m new file mode 100644 index 00000000..bc75b6e9 --- /dev/null +++ b/codec2/branches/0.7/octave/rfdesign.m @@ -0,0 +1,77 @@ +% rfdesign.m +% +% David Rowe Nov 2015 +% +% Helper functions for RF Design + +1; + + +% convert a parallel R/X to a series R/X + +function Zs = zp_to_zs(Zp) + Xp = j*imag(Zp); Rp = real(Zp); + Zs = Xp*Rp/(Xp+Rp); +endfunction + + +% convert a series R/X to a parallel R/X + +function Zp = zs_to_zp(Zs) + Xs = imag(Zs); Rs = real(Zs); + Q = Xs/Rs; + Rp = (Q*Q+1)*Rs; + Xp = Rp/Q; + Zp = Rp + j*Xp; +endfunction + + +% Design a Z match network with a parallel and series reactance +% to match between a low and high resistance. Note Xp and Xs +% must be implemented as opposite sign, ie one a inductor, one +% a capacitor (your choice). +% +% /--Xs--+---\ +% | | | +% Rlow Xp Rhigh +% | | | +% \------+---/ +% + +function [Xs Xp] = z_match(Rlow, Rhigh) + assert(Rlow < Rhigh, "Rlow must be < Rhigh"); + Q = sqrt(Rhigh/Rlow -1); + Xs = Q*Rlow; + Xp = Rhigh/Q; +endfunction + + +% Design an air core inductor, Example 1-5 "RF Circuit Design" + +function Nturns = design_inductor(L_uH, diameter_mm) + Nturns = sqrt(29*L_uH/(0.394*(diameter_mm*0.1/2))); +endfunction + + +% Work out series resistance Rl of series resonant inductor. Connect +% tracking generator to spec-an input, the series LC to ground. V is +% the ref TG level (e.g. with perfect 50 ohm term) in volts, Vmin is the +% minumum at series res freq. +% +% /-50-+---+ +% | | | +% TG C 50 spec-an +% | | | +% | L | +% | | | +% | Rl | +% | | | +% \----+---/ + +function Rl = find_rl(V,Vmin) + % at series resonance effect of C and L goes away and we are left with + % parallel combination of Ls and spec-an 50 ohm input impedance + + Rp = Vmin*50/(2*V*(1-Vmin/(2*V))); + Rl = 1/(1/Rp - 1/50) +endfunction diff --git a/codec2/branches/0.7/octave/s_param_rf.m b/codec2/branches/0.7/octave/s_param_rf.m new file mode 100644 index 00000000..8c5186af --- /dev/null +++ b/codec2/branches/0.7/octave/s_param_rf.m @@ -0,0 +1,206 @@ +% s_param_rf.m +% +% David Rowe Nov 2015 +% +% Working for small signal VHF amplifier design using +% S-param techniques from "RF Circuit Design" by Chris Bowick + +rfdesign; % library of helped functions + +more off; + +Ic = 0.014; + +% BRF92 VCE=5V Ic=5mA 100MHz + +if Ic == 0.005 + S11 = 0.727*exp(j*(-43)*pi/180); + S12 = 0.028*exp(j*(69.6)*pi/180); + S21 = 12.49*exp(j*(147)*pi/180); + S22 = 0.891*exp(j*(-16)*pi/180); +end + +% BRF92 VCE=10V Ic=14mA 100MHz + +if Ic == 0.02 + S11 = 0.548*exp(j*(-56.8)*pi/180); + S12 = 0.020*exp(j*(67.8)*pi/180); + S21 = 20.43*exp(j*(133.7)*pi/180); + S22 = 0.796*exp(j*(-18.5)*pi/180); +end + +% Stability + +Ds = S11*S22-S12*S21; +Knum = 1 + abs(Ds)^2 - abs(S11)^2 - abs(S22)^2; +Kden = 2*abs(S21)*abs(S12); +K = Knum/Kden % If > 1 unconditionally stable + % If < 1 panic +figure(1); +clf +scCreate; + +if K < 1 + C1 = S11 - Ds*conj(S22); + C2 = S22 - Ds*conj(S11); + rs1 = conj(C1)/(abs(S11)^2-abs(Ds)^2); % centre of input stability circle + ps1 = abs(S12*S21/(abs(S11)^2-abs(Ds)^2)); % radius of input stability circle + rs2 = conj(C2)/(abs(S22)^2-abs(Ds)^2); % centre of input stability circle + ps2 = abs(S12*S21/(abs(S22)^2-abs(Ds)^2)); % radius of input stability circle + + s(1,1)=S11; s(1,2)=S12; s(2,1)=S21; s(2,2)=S22; + plotStabilityCircles(s) +end + +% Gain circle + +D2 = abs(S22)^2-abs(Ds)^2; +C2 = S22 - Ds*conj(S11); +GdB = 20; Glin = 10^(GdB/10); % lets shoot for 20dB gain +G = Glin/(abs(S21)^2); +r0 = G*conj(C2)/(1+D2*G); % centre of gain circle +p0 = sqrt(1 - 2*K*abs(S12*S21)*G + (abs(S12*S21)^2)*(G^2))/(1+D2*G); % radius of gain circle + +scAddCircle(abs(r0),angle(r0)*180/pi,p0,'g') +printf("Green is the %3.1f dB constant gain circle for gammaL\n",GdB); + +% Note different design procedures for different operating points + +if Ic == 0.005 + % Choose a gammaL on the gain circle + + gammaL = 0.8 - 0.4*j; + + % Caclulate gammaS and make sure it's stable by visual inspection + % compared to stability circle. + + gammaS = conj(S11 + ((S12*S21*gammaL)/(1 - (gammaL*S22)))); +end + +if Ic == 0.014 + + % lets set zo (normalised Zo) based on Pout and get gammaL from that + + Pout = 0.01; + Irms = 0.002; + Zo = Pout/(Irms*Irms); + zo = Zo/50; + [magL,angleL] = ztog(zo); + gammaL = magL*exp(j*angleL*pi/180); + + % calculate gammaS + + gammaS = conj(S11 + ((S12*S21*gammaL)/(1 - (gammaL*S22)))); + +end + +[zo Zo] = gtoz(abs(gammaL), angle(gammaL)*180/pi,50); +[zi Zi] = gtoz(abs(gammaS), angle(gammaS)*180/pi,50); + +scAddPoint(zi); +scAddPoint(zo); + +% Transducer gain + +Gt_num = (abs(S21)^2)*(1-abs(gammaS)^2)*(1-abs(gammaL)^2); +Gt_den = abs((1-S11*gammaS)*(1-S22*gammaL) - S12*S21*gammaL*gammaS)^2; +Gt = Gt_num/Gt_den; + +if Ic == 0.005 + + % Lets design the z match for the input ------------------------------ + + % put input impedance in parallel form + + Zip = zs_to_zp(Zi); + + % first match real part of impedance + + Rs = 50; Rl = real(Zip); + [Xs Xp] = z_match(Rs,Rl); + + % Modify Xp so transistor input sees conjugate match to Zi + % Lets make Xp a capacitor, so negative sign + + Xp_match = -Xp - imag(Zip); + + % Now convert to real component values + + w = 2*pi*150E6; + Ls = Xs/w; diameter_mm = 6.25; + Ls_turns = design_inductor(Ls*1E6, diameter_mm); + Cp = 1/(w*(-Xp_match)); + + printf("Transducer gain: %3.1f dB\n", 10*log10(Gt)); + printf("Input: Zi = %3.1f + %3.1fj ohms\n", real(Zi), imag(Zi)); + printf(" In parallel form Rp = %3.1f Xp = %3.1fj ohms\n", real(Zip), imag(Zip)); + printf(" So for a conjugate match transistor input wants to see:\n Rp = %3.1f Xp = %3.1fj ohms\n", real(Zip), -imag(Zip)); + printf(" Rs = %3.1f to Rl = %3.1f ohm matching network Xs = %3.1fj Xp = %3.1fj\n", Rs, Rl, Xs, Xp); + printf(" with conj match to Zi Xs = %3.1fj Xp = %3.1fj\n", Xs, Xp_match); + printf(" matching components Ls = %5.3f uH Cp = %4.1f pF\n", Ls*1E6, Cp*1E12); + printf(" Ls can be made from %3.1f turns on a %4.2f mm diameter air core\n", Ls_turns, diameter_mm); + + % Now Z match for output ------------------------------------- + + Lo = -imag(Zo)/w; + Lo_turns = design_inductor(Lo*1E6, diameter_mm); + printf("Output: Zo = %3.1f + %3.1fj ohms\n", real(Zo), imag(Zo)); + printf(" So for a conjugate match transistor output wants to see:\n Rl = %3.1f Xl = %3.1fj ohms\n", real(Zo), -imag(Zo)); + printf(" Which is a series inductor Lo = %5.3f uH\n", Lo*1E6); + printf(" Lo can be made from %3.1f turns on a %4.2f mm diameter air core\n", Lo_turns, diameter_mm); +end + + +if Ic == 0.014 + printf("Transducer gain: %3.1f dB\n", 10*log10(Gt)); + + % Lets design the z match for the input ------------------------------ + + % put input impedance in parallel form + + Zip = zs_to_zp(Zi); + + % first match real part of impedance + + Rs = 50; Rl = real(Zip); + [Xs Xp] = z_match(Rl,Rs); + + % Lets make Xs a capacitir to block DC, so Xp is an inductor. + % Modify Xs so transistor input sees conjugate match to Zi. Xs is a + % capacitor, so reactance is negative + + Xs_match = -Xs - imag(Zip); + + % Now convert to real component values + + w = 2*pi*150E6; diameter_mm = 6.25; + Li = Xp/w; + Li_turns = design_inductor(Li*1E6, diameter_mm); + Ci = 1/(w*(-Xs_match)); + + printf("Input: Zi = %3.1f + %3.1fj ohms\n", real(Zi), imag(Zi)); + printf(" In parallel form Rp = %3.1f Xp = %3.1fj ohms\n", real(Zip), imag(Zip)); + printf(" So for a conjugate match transistor input wants to see:\n Rp = %3.1f Xp = %3.1fj ohms\n", real(Zip), -imag(Zip)); + printf(" Rs = %3.1f to Rl = %3.1f ohm matching network Xs = %3.1fj Xp = %3.1fj\n", Rs, Rl, Xs, Xp); + printf(" with Xs a capacitor, and Xp and inductor Xs = %3.1fj Xp = %3.1fj\n", -Xs, Xp); + printf(" With a conj match to Zi Xs = %3.1fj Xp = %3.1fj\n", Xs_match, Xp); + printf(" matching components Li = %5.3f uH Ci = %4.1f pF\n", Li*1E6, Ci*1E12); + printf(" Li can be made from %3.1f turns on a %4.2f mm diameter air core\n", Li_turns, diameter_mm); + + % Design output Z match ---------------------------------------------- + + Rs = real(Zo); Rl = 50; + [Xs Xp] = z_match(Rl,Rs); + + % Lets make XP an inductor so it can double as a RF choke, and Xp as + % a capacitor will give us a convenient DC block + + w = 2*pi*150E6; diameter_mm = 6.25; + Lo = Xp/w; Lo_turns = design_inductor(Lo*1E6, diameter_mm); + Co = 1/(w*Xs); + printf("Output: Zo = %3.1f + %3.1fj ohms\n", real(Zo), imag(Zo)); + printf(" matching network Xp = %3.1f X = %3.1f ohms\n", Xp, Xs); + printf(" which is parallel Lo = %5.3f uH and series Co = %4.1f pF\n", Lo*1E6, Co*1E12); + printf(" Lo can be made from %3.1f turns on a %4.2f mm diameter air core\n", Lo_turns, diameter_mm); +end + diff --git a/codec2/branches/0.7/octave/sample_clock_offset.m b/codec2/branches/0.7/octave/sample_clock_offset.m new file mode 100644 index 00000000..51691782 --- /dev/null +++ b/codec2/branches/0.7/octave/sample_clock_offset.m @@ -0,0 +1,21 @@ +% sample_clock_offset.m +% +% David Rowe June 2017 +% +% To simulate a sample clock offset we resample by a small amount +% using linear interpolation + +function rx = sample_clock_offset(tx, sample_clock_offset_ppm) + tin=1; + tout=1; + rx = zeros(1,length(tx)); + while tin < length(tx) + t1 = floor(tin); + t2 = ceil(tin); + f = tin - t1; + rx(tout) = (1-f)*tx(t1) + f*tx(t2); + tout += 1; + tin += 1+sample_clock_offset_ppm/1E6; + end +end + diff --git a/codec2/branches/0.7/octave/save_array_c_header.m b/codec2/branches/0.7/octave/save_array_c_header.m new file mode 100644 index 00000000..0a6800d3 --- /dev/null +++ b/codec2/branches/0.7/octave/save_array_c_header.m @@ -0,0 +1,14 @@ +% save_array_c_header.m +% +% David Rowe Sep 2015 + +function save_array_c_header(array, array_name, filename) + f=fopen(filename,"wt"); + fprintf(f,"/* Generated by save_array_c_header.m Octave function */\n\n"); + fprintf(f,"const int %s[]={\n", array_name); + for m=1:length(array)-1 + fprintf(f," %f,\n",array(m)); + endfor + fprintf(f," %f\n};\n",array(length(array))); + fclose(f); +endfunction diff --git a/codec2/branches/0.7/octave/save_raw.m b/codec2/branches/0.7/octave/save_raw.m new file mode 100644 index 00000000..7f17277e --- /dev/null +++ b/codec2/branches/0.7/octave/save_raw.m @@ -0,0 +1,7 @@ +% save_raw.m +% David Rowe 9 Feb 2015 + +function s = save_raw(fn,s) + fs=fopen(fn,"wb"); + fwrite(fs,s,"short"); +endfunction diff --git a/codec2/branches/0.7/octave/sd.m b/codec2/branches/0.7/octave/sd.m new file mode 100644 index 00000000..a5352928 --- /dev/null +++ b/codec2/branches/0.7/octave/sd.m @@ -0,0 +1,170 @@ +% sd.m +% David Rowe Aug 2012 +% Plots the spectal distorion between twofiles of LPCs. Used for LSP +% quantisation tuning. + +function sd(raw_filename, dump_file_prefix, f) + + graphics_toolkit ("gnuplot"); + + e_filename = sprintf("%s_E.txt", dump_file_prefix); + e = load(e_filename); + ak1_filename = sprintf("%s_ak.txt", dump_file_prefix); + ak2_filename = sprintf("%s_ak_.txt", dump_file_prefix); + ak1 = load(ak1_filename); + ak2 = load(ak2_filename); + + [ak1_r, ak1_c] = size(ak1) + [ak2_r, ak2_c] = size(ak2) + + frames = max([ak1_r ak2_r]); printf("%d frames\n", frames); + sd = zeros(1,frames); + Ndft = 512; + A1 = zeros(frames, Ndft); + A2 = zeros(frames, Ndft); + + % initial helicopter view of all frames + + spec_err = zeros(1, Ndft); + for i = 1:frames + A1(i,:) = -20*log10(abs(fft(ak1(i,:),Ndft))); + A2(i,:) = -20*log10(abs(fft(ak2(i,:),Ndft))); + sd(i) = sum((A1(i,:) - A2(i,:)).^2)/Ndft; + spec_err += (A1(i,:) - A2(i,:)).^2; + end + spec_err /= frames; + printf("sd av %3.2f dB*dB\n", sum(sd)/frames); + + % work out worst frames with sig energy + + ind = find(e < 0); + sd(ind) = 0; + [largest largest_ind] = sort(sd,"descend"); + printf("largest SD frames....: %3.2f\n", largest(1:5)); + printf("largest SD frames ind: %d\n", largest_ind(1:5)); + + figure(1); + clf; + subplot(211) + fs=fopen(raw_filename,"rb"); + s = fread(fs,Inf,"short"); + plot(s); + axis([1 length(s) -20E3 20E3]) + subplot(212) + [a b c] = plotyy(1:frames, sd, 1:frames, e); + %axis(a, [1 frames 0 10]) + + lsp1_filename = sprintf("%s_lsp.txt", dump_file_prefix); + lsp2_filename = sprintf("%s_lsp_.txt", dump_file_prefix); + lsp1 = load(lsp1_filename); + lsp2 = load(lsp2_filename); + + mel_filename = sprintf("%s_mel.txt", dump_file_prefix); + mel = load(mel_filename); + + weights_filename = sprintf("%s_weights.txt", dump_file_prefix); + if file_in_path(".",weights_filename) + weights = load(weights_filename); + end + + figure(4) + plot(e,sd,'+') + axis([0 50 0 10]) + xlabel('LPC energy dB') + ylabel('SD dB*dB'); + + figure(5) + subplot(211) + ind = find(e > 0); + hist(sd(ind)) + title('Histogram of SD'); + subplot(212) + plot((1:Ndft)*8000/Ndft, spec_err) + axis([300 3000 0 max(spec_err)]) + title('Average error across spectrum') + + mel_indexes_filename = sprintf("%s_mel_indexes.txt", dump_file_prefix); + if 0 %file_in_path(".", mel_indexes_filename) + mel_indexes = load(mel_indexes_filename); + figure(6) + bins = [15, 7, 15, 7, 7, 7]; + ind = find(e > 5); % ignore silence frames + for i=1:6 + subplot(3,2,i) + hist(mel_indexes(ind,i),0:bins(i)) + ylab = sprintf("index %d", i); + ylabel(ylab); + end + end + + % now enter single step mode so we can analyse each frame + k = ' '; + largest_mode = 0; + do + if largest_mode + fr = largest_ind(f); + else + fr = f; + endif + + figure(2); + clf; + plot((4000/pi)*lsp1((fr-2:fr+2),:)); + hold on; + plot((4000/pi)*lsp2((fr-2:fr+2),:),'+-'); + hold off; + + figure(3); + clf; + + plot((1:Ndft/2)*4000/(Ndft/2), A1(fr,1:(Ndft/2)),";A enc;r"); + axis([1 4000 -20 40]); + hold on; + plot((1:Ndft/2)*4000/(Ndft/2), A2(fr,1:(Ndft/2)),";A dec;"); + if file_in_path(".",weights_filename) + plot(lsp1(fr,:)*4000/pi, weights(fr,:),";weights;g+"); + end + + printf("\n"); + for l=1:10 + plot([lsp1(fr,l)*4000/pi lsp1(fr,l)*4000/pi], [0 -10], 'r'); + plot([lsp2(fr,l)*4000/pi lsp2(fr,l)*4000/pi], [-10 -20], 'b'); + plot([mel(fr,l) mel(fr,l)], [0 10], 'g'); + printf("%d ", mel(fr,l)); + endfor + printf("\n"); + + plot(0,0,';lsp enc;r'); + plot(0,0,';lsp dec;b'); + plot(0,0,';mel dec;g'); + sd_str = sprintf(";sd %3.2f dB*dB;", sd(f)); + plot(0,0,sd_str); + + hold off; + + % interactive menu + + printf("\rframe: %d menu: n-next b-back l-largest mode q-quit", fr); + fflush(stdout); + k = kbhit(); + if (k == 'n') + f = f + 1; + endif + if (k == 'b') + f = f - 1; + endif + + if (k == 'l') + if largest_mode + largest_mode = 0; + else + largest_mode = 1; + f = 1; + endif + endif + + until (k == 'q') + printf("\n"); + +endfunction + diff --git a/codec2/branches/0.7/octave/spec.m b/codec2/branches/0.7/octave/spec.m new file mode 100644 index 00000000..d556b906 --- /dev/null +++ b/codec2/branches/0.7/octave/spec.m @@ -0,0 +1,86 @@ +% spec.m +% Jean Marc Valin +% +% Spectrogram function for Octave +% +% Copyright (c) John-Marc Valin 2012 +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions +% are met: +% +% - Redistributions of source code must retain the above copyright +% notice, this list of conditions and the following disclaimer. +% +% - Redistributions in binary form must reproduce the above copyright +% notice, this list of conditions and the following disclaimer in the +% documentation and/or other materials provided with the distribution. +% +% - Neither the name of Jean Marc Valin nor the names of its +% contributors may be used to endorse or promote products derived from +% this software without specific prior written permission. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +% ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +% LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +% A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR +% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +% EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +% PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +% LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +% SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function X = spec(x, Fs, framesize, start, stop) + + +gr=[zeros(1024,1),[0:1023]'/1023,.68*[0:1023]'/1023]; + +%gr=[.4*[0:1023]'/1023,[0:1023]'/1023,.68*[0:1023]'/1023]; + +%t=[0:1023]'/1023; +%t=(1+.25*t-cos(pi*t))/2.25; +%gr = [zeros(1024,1),t,.68*t]; + + +%colormap(gr); + +if nargin < 2 || isempty(Fs) + Fs = 44100; +end + +if nargin < 3 || isempty(framesize) + framesize = 2048; +endif + +offset = framesize/8; + +X = 20*log10(abs(specgram(x, framesize, 48000, blackmanharris(framesize)', framesize-offset))); + +XM=max(max(X)); +X = max(XM-30,X); +%size(X) +F = -[framesize/2-1:-1:0]/framesize*Fs; +%F = [0:127]/128*24000; +T=[1:size(X,2)]/Fs*offset; +%imagesc(X(end:-1:1,:)); + +if nargin < 4 || isempty(start) + istart=1; +else + istart = round(start*Fs/offset); +end + +if nargin < 5 || isempty(stop) + istop = size(X,2); +else + istop = round(stop*Fs/offset); +endif + +istart = max(1,istart); +istop = min(istop, size(X,2)); + +imagesc(T(1+istart:istop), F, X(end:-1:1,1+istart:istop)); + +X = X(:,1+istart:istop); diff --git a/codec2/branches/0.7/octave/tcohpsk.m b/codec2/branches/0.7/octave/tcohpsk.m new file mode 100644 index 00000000..59ddae01 --- /dev/null +++ b/codec2/branches/0.7/octave/tcohpsk.m @@ -0,0 +1,753 @@ +% tcohpsk.m +% David Rowe Oct 2014 +% +% Octave coherent PSK modem script that hs two modes: +% +% i) tests the C port of the coherent PSK modem. This script loads +% the output of unittest/tcohpsk.c and compares it to the output of +% the reference versions of the same modem written in Octave. +% + +% (ii) Runs the Octave version of the cohpsk modem to tune and develop +% it, including extensive channel simulations such as AWGN noise, +% fading/HF, frequency offset, frequency drift, and tx/rx sample +% rate differences. + +% TODO: +% +% [X] Test +% [X] AWGN channel +% [X] freq offset +% [X] fading channel +% [X] freq drift +% [X] timing drift +% [X] tune perf/impl loss to get closer to ideal +% [X] linear interp of phase for better fading perf +% [X] freq offset/drift feedback loop +% [X] PAPR measurement and reduction +% [X] false sync +% [X] doesn't sync up on noise (used EsNo = -12) +% [X] similar but invalid signal like huge f off +% [X] ability to "unsync" when signal dissapears +% [ ] some calibrated tests against FreeDV 1600 +% + compare sound quality at various Es/Nos +% [ ] sync +% + set some req & implement +% [ ] way to handle eom w/o nasties +% + like mute ouput when signal has gone or v low snr +% + instantaneous snr +% [X] ssb tx filter with 3dB passband ripple +% + diverisity helped for AWGN BER 0.024 down to 0.016 +% + Only a small change in fading perf with filter on/off +% + however other filters may have other effects, should test this, +% e.g. scatter plots, some sort of BER metric? +% [X] EsNo estimation +% [ ] filter reqd with compression? +% + make sure not too much noise passed into noise floor +% [X] different diversity combination +% + taking largest symbol didn't help +% [X] histogram of bit errors +% + lot of data +% + ssb filter +% + compression +% + make sure it's flat with many errors + +graphics_toolkit ("gnuplot"); +more off; + +cohpsk; +fdmdv; +autotest; + +rand('state',1); +randn('state',1); + +% select which test ---------------------------------------------------------- + +test = 'compare to c'; +%test = 'awgn'; +%test = 'fading'; + +% some parameters that can be over ridden, e.g. to disable parts of modem + +initial_sync = 0; % setting this to 1 put us straight into sync w/o freq offset est +ftrack_en = 1; % set to 1 to enable freq tracking +ssb_tx_filt = 0; % set to 1 to to simulate SSB tx filter with passband ripple +Fs = 7500; + +% predefined tests .... + +if strcmp(test, 'compare to c') + frames = 100; + foff = 58.7; + dfoff = -0.5/Fs; + EsNodB = 8; + fading_en = 0; + hf_delay_ms = 2; + compare_with_c = 1; + sample_rate_ppm = -1500; + ssb_tx_filt = 0; +end + +% should be BER around 0.015 to 0.02 + +if strcmp(test, 'awgn') + frames = 100; + foff = 58.7; + dfoff = -0.5/Fs; + EsNodB = 8; + fading_en = 0; + hf_delay_ms = 2; + compare_with_c = 0; + sample_rate_ppm = 0; +end + +% Similar to AWGN - should be BER around 0.015 to 0.02 + +if strcmp(test, 'fading'); + frames = 100; + foff = -25; + dfoff = 0.5/Fs; + EsNodB = 12; + fading_en = 1; + hf_delay_ms = 2; + compare_with_c = 0; + sample_rate_ppm = 0; +end + +EsNo = 10^(EsNodB/10); + +% modem constants ---------------------------------------------------------- + +Rs = 75; % symbol rate in Hz +Nc = 7; % number of carriers +Nd = 2; % diveristy factor +framesize = 56; % number of payload data bits in the frame + +Nsw = 4; % frames we demod for initial sync window +afdmdv.Nsym = 6; % size of tx/tx root nyquist filter in symbols +afdmdv.Nt = 5; % number of symbols we estimate timing over + +clip = 6.5; % Clipping of tx signal to reduce PAPR. Adjust by + % experiment as Nc and Nd change. Check out no noise + % scatter diagram and AWGN/fading BER perf + % at operating points + +% FDMDV init --------------------------------------------------------------- + +afdmdv.Fs = Fs; +afdmdv.Nc = Nd*Nc-1; +afdmdv.Rs = Rs; +if Fs/afdmdv.Rs != floor(Fs/afdmdv.Rs) + printf("\n Oops, Fs/Rs must be an integer!\n\n"); + return +end + +M = afdmdv.M = afdmdv.Fs/afdmdv.Rs; +afdmdv.Nfilter = afdmdv.Nsym*M; +afdmdv.tx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter); +excess_bw = 0.5; +afdmdv.gt_alpha5_root = gen_rn_coeffs(excess_bw, 1/Fs, Rs, afdmdv.Nsym, afdmdv.M); + +Fcentre = afdmdv.Fcentre = 1500; +afdmdv.Fsep = afdmdv.Rs*(1+excess_bw); +afdmdv.phase_tx = ones(afdmdv.Nc+1,1); +% non linear carrier spacing, combined with clip, helps PAPR a lot! +freq_hz = afdmdv.Fsep*( -Nc*Nd/2 - 0.5 + (1:Nc*Nd).^0.98 ) +afdmdv.freq_pol = 2*pi*freq_hz/Fs; +afdmdv.freq = exp(j*afdmdv.freq_pol); +afdmdv.Fcentre = 1500; + +afdmdv.fbb_rect = exp(j*2*pi*Fcentre/Fs); +afdmdv.fbb_phase_tx = 1; +afdmdv.fbb_phase_rx = 1; + +afdmdv.Nrxdec = 31; +afdmdv.rxdec_coeff = fir1(afdmdv.Nrxdec-1, 0.25)'; +afdmdv.rxdec_lpf_mem = zeros(1,afdmdv.Nrxdec-1+afdmdv.M); + +P = afdmdv.P = 4; +afdmdv.phase_rx = ones(afdmdv.Nc+1,1); +afdmdv.Nfilter = afdmdv.Nsym*afdmdv.M; +afdmdv.rx_fdm_mem = zeros(1,afdmdv.Nfilter + afdmdv.M); +Q = afdmdv.Q = afdmdv.M/4; +if Q != floor(Q) + printf("\n Yeah .... if (Fs/Rs)/4 = M/4 isn't an integer we will just go and break things.\n\n"); +end + +afdmdv.rx_filter_mem_timing = zeros(afdmdv.Nc+1, afdmdv.Nt*afdmdv.P); +afdmdv.Nfiltertiming = afdmdv.M + afdmdv.Nfilter + afdmdv.M; + +afdmdv.rx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter); + +afdmdv.filt = 0; +afdmdv.prev_rx_symb = ones(1,afdmdv.Nc+1); + +% COHPSK Init -------------------------------------------------------- + +acohpsk = standard_init(); +acohpsk.framesize = framesize; +acohpsk.ldpc_code = 0; +acohpsk.ldpc_code_rate = 1; +acohpsk.Nc = Nc; +acohpsk.Rs = Rs; +acohpsk.Ns = 4; +acohpsk.coh_en = 1; +acohpsk.Nd = Nd; +acohpsk.modulation = 'qpsk'; +acohpsk.do_write_pilot_file = 1; % enable this to dump pilot symbols to C .h file, e.g. if frame params change +acohpsk = symbol_rate_init(acohpsk); +acohpsk.Ndft = 1024; +acohpsk.f_est = afdmdv.Fcentre; + +ch_fdm_frame_buf = zeros(1, Nsw*acohpsk.Nsymbrowpilot*afdmdv.M); + +% ----------------------------------------------------------- + +tx_bits_log = []; +tx_symb_log = []; +rx_amp_log = []; +rx_phi_log = []; +ch_symb_log = []; +rx_symb_log = []; +rx_bits_log = []; +tx_bits_prev_log = []; +uvnoise_log = []; +nerr_log = []; +tx_baseband_log = []; +tx_fdm_frame_log = []; +ch_fdm_frame_log = []; +rx_fdm_frame_bb_log = []; +rx_filt_log = []; +rx_fdm_filter_log = []; +rx_baseband_log = []; +rx_fdm_frame_log = []; +ct_symb_ff_log = []; +rx_timing_log = []; +ratio_log = []; +foff_log = []; +f_est_log = []; +sig_rms_log = []; +noise_rms_log = []; +noise_rms_filt_log = []; + +% Channel modeling and BER measurement ---------------------------------------- + +rand('state',1); +tx_bits_coh = round(rand(1,framesize*10)); +ptx_bits_coh = 1; + +Nerrs = Tbits = 0; +prev_tx_bits = prev_tx_bits2 = []; +error_positions_hist = zeros(1,framesize); + +phase_ch = 1; +sync = initial_sync; +acohpsk.f_est = Fcentre; +acohpsk.f_fine_est = 0; +acohpsk.ct = 4; +acohpsk.ftrack_en = ftrack_en; + +[spread spread_2ms hf_gain] = init_hf_model(Fs, frames*acohpsk.Nsymbrowpilot*afdmdv.M); +hf_n = 1; +nhfdelay = floor(hf_delay_ms*Fs/1000); +ch_fdm_delay = zeros(1, acohpsk.Nsymbrowpilot*M + nhfdelay); + +% simulated SSB tx filter + +[b, a] = cheby1(4, 3, [600, 2600]/(Fs/2)); +[y filt_states] = filter(b,a,0); +h = freqz(b,a,(600:2600)/(Fs/(2*pi))); +filt_gain = (2600-600)/sum(abs(h) .^ 2); % ensures power after filter == before filter + +noise_rms_filt = 0; + +% main loop -------------------------------------------------------------------- + +% run mod and channel as aseparate loop so we can resample to simulate sample rate differences + +for f=1:frames + tx_bits = tx_bits_coh(ptx_bits_coh:ptx_bits_coh+framesize-1); + ptx_bits_coh += framesize; + if ptx_bits_coh > length(tx_bits_coh) + ptx_bits_coh = 1; + end + + tx_bits_log = [tx_bits_log tx_bits]; + + [tx_symb tx_bits] = bits_to_qpsk_symbols(acohpsk, tx_bits, [], []); + tx_symb_log = [tx_symb_log; tx_symb]; + + tx_fdm_frame = []; + for r=1:acohpsk.Nsymbrowpilot + tx_onesymb = tx_symb(r,:); + [tx_baseband afdmdv] = tx_filter(afdmdv, tx_onesymb); + tx_baseband_log = [tx_baseband_log tx_baseband]; + [tx_fdm afdmdv] = fdm_upconvert(afdmdv, tx_baseband); + tx_fdm_frame = [tx_fdm_frame tx_fdm]; + end + + % clipping, which along with non-linear carrier spacing, improves PAPR + % The value of clip is a function of Nc and is adjusted experimentally + % such that the BER hit over no clipping at Es/No=8dB is small. + + ind = find(abs(tx_fdm_frame) > clip); + tx_fdm_frame(ind) = clip*exp(j*angle(tx_fdm_frame(ind))); + + tx_fdm_frame_log = [tx_fdm_frame_log tx_fdm_frame]; + + % + % Channel -------------------------------------------------------------------- + % + + % simulate tx SSB filter with ripple + + if ssb_tx_filt + [tx_fdm_frame filt_states] = filter(b,a,sqrt(filt_gain)*tx_fdm_frame, filt_states); + end + + % frequency offset and frequency drift + + ch_fdm_frame = zeros(1,acohpsk.Nsymbrowpilot*M); + for i=1:acohpsk.Nsymbrowpilot*M + foff_rect = exp(j*2*pi*foff/Fs); + foff += dfoff; + phase_ch *= foff_rect; + ch_fdm_frame(i) = tx_fdm_frame(i) * phase_ch; + end + foff_log = [foff_log foff]; + phase_ch /= abs(phase_ch); + % printf("foff: %f ", foff); + + % optional fading + + if fading_en + ch_fdm_delay(1:nhfdelay) = ch_fdm_delay(acohpsk.Nsymbrowpilot*M+1:nhfdelay+acohpsk.Nsymbrowpilot*M); + ch_fdm_delay(nhfdelay+1:nhfdelay+acohpsk.Nsymbrowpilot*M) = ch_fdm_frame; + + for i=1:acohpsk.Nsymbrowpilot*M + ahf_model = hf_gain*(spread(hf_n)*ch_fdm_frame(i) + spread_2ms(hf_n)*ch_fdm_delay(i)); + ch_fdm_frame(i) = ahf_model; + hf_n++; + end + end + + % each carrier has power = 2, total power 2Nc, total symbol rate NcRs, noise BW B=Fs + % Es/No = (C/Rs)/(N/B), N = var = 2NcFs/NcRs(Es/No) = 2Fs/Rs(Es/No) + + variance = 2*Fs/(acohpsk.Rs*EsNo); + uvnoise = sqrt(0.5)*(randn(1,acohpsk.Nsymbrowpilot*M) + j*randn(1,acohpsk.Nsymbrowpilot*M)); + uvnoise_log = [uvnoise_log uvnoise]; + noise = sqrt(variance)*uvnoise; + + ch_fdm_frame += noise; + + ch_fdm_frame_log = [ch_fdm_frame_log ch_fdm_frame]; +end + +% simulate difference in sample clocks + +%ch_fdm_frame_log = resample(ch_fdm_frame_log, (1E6 + sample_rate_ppm), 1E6); + +tin=1; +tout=1; +ch_fdm_frame_log_out = zeros(1,length(ch_fdm_frame_log)); +while tin < length(ch_fdm_frame_log) + t1 = floor(tin); + t2 = ceil(tin); + f = tin - t1; + ch_fdm_frame_log_out(tout) = (1-f)*ch_fdm_frame_log(t1) + f*ch_fdm_frame_log(t2); + tout += 1; + tin += 1+sample_rate_ppm/1E6; + %printf("tin: %f tout: %f f: %f\n", tin, tout, f); +end +ch_fdm_frame_log = ch_fdm_frame_log_out(1:tout-1); +%ch_fdm_frame_log *= 5000; + +%ch_fdm_frame_log = real(ch_fdm_frame_log); + +% Now run demod ---------------------------------------------------------------- + +%ch_fdm_frame_log = load_raw("~/fdmdv2-dev/build_linux/tmp.raw"); +%ch_fdm_frame_log = ch_fdm_frame_log(M:length(ch_fdm_frame_log)); +%ch_fdm_frame_log /= 5000; + +%frames = floor(acohpsk.Nsymbrowpilot*M); + +ch_fdm_frame_log_index = 1; +nin = M; +f = 0; +nin_frame = acohpsk.Nsymbrowpilot*M; + +%while (ch_fdm_frame_log_index + acohpsk.Nsymbrowpilot*M+M/P) < length(ch_fdm_frame_log) +for f=1:frames; + acohpsk.frame = f; + + ch_fdm_frame = ch_fdm_frame_log(ch_fdm_frame_log_index:ch_fdm_frame_log_index + nin_frame - 1); + ch_fdm_frame_log_index += nin_frame; + + % + % Demod ---------------------------------------------------------------------- + % + + % store two frames of received samples so we can rewind if we get a good candidate + + ch_fdm_frame_buf(1:Nsw*acohpsk.Nsymbrowpilot*M-nin_frame) = ch_fdm_frame_buf(nin_frame+1:Nsw*acohpsk.Nsymbrowpilot*M); + ch_fdm_frame_buf(Nsw*acohpsk.Nsymbrowpilot*M-nin_frame+1:Nsw*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame; + + next_sync = sync; + + % if out of sync do Initial Freq offset estimation over NSW frames to flush out memories + + if (sync == 0) + + % we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz + + max_ratio = 0; + for acohpsk.f_est = Fcentre-40:40:Fcentre+40 +% for acohpsk.f_est = Fcentre + + printf(" [%d] acohpsk.f_est: %f +/- 20\n", f, acohpsk.f_est); + + % we are out of sync so reset f_est and process two frames to clean out memories + + [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0); + rx_baseband_log = [rx_baseband_log rx_baseband]; + + rx_filt_log = [rx_filt_log rx_filt]; + ch_symb_log = [ch_symb_log; ch_symb]; + rx_timing_log = [rx_timing_log rx_timing]; + + for i=1:Nsw-1 + acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot); + end + [anext_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync); + + if anext_sync == 1 + %printf(" [%d] acohpsk.ratio: %f\n", f, acohpsk.ratio); + if acohpsk.ratio > max_ratio + max_ratio = acohpsk.ratio; + f_est = acohpsk.f_est - acohpsk.f_fine_est; + next_sync = anext_sync; + end + end + end + + if next_sync == 1 + + % we've found a sync candidate! + % re-process last two frames with adjusted f_est then check again + + acohpsk.f_est = f_est; + + printf(" [%d] trying sync and f_est: %f\n", f, acohpsk.f_est); + + [ch_symb rx_timing rx_filt rx_baseband afdmdv f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0); + rx_baseband_log = [rx_baseband_log rx_baseband]; + rx_filt_log = [rx_filt_log rx_filt]; + ch_symb_log = [ch_symb_log; ch_symb]; + rx_timing_log = [rx_timing_log rx_timing]; + + for i=1:Nsw-1 + acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot); + end + [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync); + if abs(acohpsk.f_fine_est) > 2 + printf(" [%d] Hmm %f is a bit big so back to coarse est ...\n", f, acohpsk.f_fine_est); + next_sync = 0; + end + + if acohpsk.ratio < 0.9 + next_sync = 0; + end + if next_sync == 1 + % OK we are in sync! + % demodulate first frame (demod completed below) + + printf(" [%d] in sync! f_est: %f ratio: %f \n", f, f_est, acohpsk.ratio); + acohpsk.ct_symb_ff_buf(1:acohpsk.Nsymbrowpilot+2,:) = acohpsk.ct_symb_buf(acohpsk.ct+1:acohpsk.ct+acohpsk.Nsymbrowpilot+2,:); + end + end + end + + % If in sync just do sample rate processing on latest frame + + if sync == 1 + [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame, acohpsk.f_est, acohpsk.Nsymbrowpilot, nin, acohpsk.ftrack_en); + [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb, sync, next_sync); + + acohpsk.ct_symb_ff_buf(1:2,:) = acohpsk.ct_symb_ff_buf(acohpsk.Nsymbrowpilot+1:acohpsk.Nsymbrowpilot+2,:); + acohpsk.ct_symb_ff_buf(3:acohpsk.Nsymbrowpilot+2,:) = acohpsk.ct_symb_buf(acohpsk.ct+3:acohpsk.ct+acohpsk.Nsymbrowpilot+2,:); + + rx_baseband_log = [rx_baseband_log rx_baseband]; + rx_filt_log = [rx_filt_log rx_filt]; + ch_symb_log = [ch_symb_log; ch_symb]; + rx_timing_log = [rx_timing_log rx_timing]; + f_est_log = [f_est_log acohpsk.f_est]; + %printf("%f\n", acohpsk.f_est); + end + + % if we are in sync complete demodulation with symbol rate processing + + if (next_sync == 1) || (sync == 1) + [rx_symb rx_bits rx_symb_linear amp_ phi_ sig_rms noise_rms] = qpsk_symbols_to_bits(acohpsk, acohpsk.ct_symb_ff_buf); + rx_symb_log = [rx_symb_log; rx_symb]; + rx_amp_log = [rx_amp_log; amp_]; + rx_phi_log = [rx_phi_log; phi_]; + rx_bits_log = [rx_bits_log rx_bits]; + tx_bits_prev_log = [tx_bits_prev_log prev_tx_bits2]; + ratio_log = [ratio_log acohpsk.ratio]; + ct_symb_ff_log = [ct_symb_ff_log; acohpsk.ct_symb_ff_buf(1:acohpsk.Nsymbrowpilot,:)]; + sig_rms_log = [sig_rms_log sig_rms]; + noise_rms_log = [noise_rms_log noise_rms]; + noise_rms_filt = 0.9*noise_rms_filt + 0.1*noise_rms; + noise_rms_filt_log = [noise_rms_filt_log noise_rms_filt]; + + % BER stats + + if f > 2 + error_positions = xor(tx_bits_log((f-3)*framesize+1:(f-2)*framesize), rx_bits); + Nerrs += sum(error_positions); + nerr_log = [nerr_log sum(error_positions)]; + Tbits += length(error_positions); + error_positions_hist += error_positions; + end + printf("\r [%d]", f); + end + + % reset BER stats if we lose sync + + if sync == 1 + %Nerrs = 0; + %Tbits = 0; + %nerr_log = []; + end + + [sync acohpsk] = sync_state_machine(acohpsk, sync, next_sync); + + % work out how many samples we need for next time + + nin = M; + if sync == 1 + if rx_timing(length(rx_timing)) > M/P + nin = M + M/P; + end + if rx_timing(length(rx_timing)) < -M/P + nin = M - M/P; + end + end + nin_frame = (acohpsk.Nsymbrowpilot-1)*M + nin; + %printf("%f %d %d\n", rx_timing(length(rx_timing)), nin, nin_frame); + + prev_tx_bits2 = prev_tx_bits; + prev_tx_bits = tx_bits; + +end + +ber = Nerrs/Tbits; +printf("\nOctave EsNodB: %4.1f ber..: %4.3f Nerrs..: %d Tbits..: %d\n", EsNodB, ber, Nerrs, Tbits); + +if compare_with_c + + % Output vectors from C port --------------------------------------------------- + + load ../build_linux/unittest/tcohpsk_out.txt + + % Determine bit error rate + + + sz = length(rx_bits_log_c); + Nerrs_c = sum(xor(tx_bits_log(1:sz-framesize), rx_bits_log_c(framesize+1:sz))); + Tbits_c = length(tx_bits_prev_log); + ber_c = Nerrs_c/Tbits_c; + printf("C EsNodB.....: %4.1f ber_c: %4.3f Nerrs_c: %d Tbits_c: %d\n", EsNodB, ber_c, Nerrs_c, Tbits_c); + + stem_sig_and_error(1, 111, tx_bits_log_c, tx_bits_log - tx_bits_log_c, 'tx bits', [1 length(tx_bits_log) -1.5 1.5]) + + stem_sig_and_error(2, 211, real(tx_symb_log_c), real(tx_symb_log - tx_symb_log_c), 'tx symb re', [1 length(tx_symb_log_c) -1.5 1.5]) + stem_sig_and_error(2, 212, imag(tx_symb_log_c), imag(tx_symb_log - tx_symb_log_c), 'tx symb im', [1 length(tx_symb_log_c) -1.5 1.5]) + + stem_sig_and_error(3, 211, real(tx_fdm_frame_log_c), real(tx_fdm_frame_log - tx_fdm_frame_log_c), 'tx fdm frame re', [1 length(tx_fdm_frame_log) -10 10]) + stem_sig_and_error(3, 212, imag(tx_fdm_frame_log_c), imag(tx_fdm_frame_log - tx_fdm_frame_log_c), 'tx fdm frame im', [1 length(tx_fdm_frame_log) -10 10]) + stem_sig_and_error(4, 211, real(ch_fdm_frame_log_c), real(ch_fdm_frame_log - ch_fdm_frame_log_c), 'ch fdm frame re', [1 length(ch_fdm_frame_log) -10 10]) + stem_sig_and_error(4, 212, imag(ch_fdm_frame_log_c), imag(ch_fdm_frame_log - ch_fdm_frame_log_c), 'ch fdm frame im', [1 length(ch_fdm_frame_log) -10 10]) + + c = 1; + stem_sig_and_error(5, 211, real(rx_baseband_log_c(c,:)), real(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'rx baseband re', [1 length(rx_baseband_log) -10 10]) + stem_sig_and_error(5, 212, imag(rx_baseband_log_c(c,:)), imag(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'rx baseband im', [1 length(rx_baseband_log) -10 10]) + stem_sig_and_error(6, 211, real(rx_filt_log_c(c,:)), real(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'rx filt re', [1 length(rx_filt_log) -1 1]) + stem_sig_and_error(6, 212, imag(rx_filt_log_c(c,:)), imag(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'rx filt im', [1 length(rx_filt_log) -1 1]) + + [n m] = size(ch_symb_log); + stem_sig_and_error(7, 211, real(ch_symb_log_c), real(ch_symb_log - ch_symb_log_c), 'ch symb re', [1 n -1.5 1.5]) + stem_sig_and_error(7, 212, imag(ch_symb_log_c), imag(ch_symb_log - ch_symb_log_c), 'ch symb im', [1 n -1.5 1.5]) + + [n m] = size(rx_symb_log); + stem_sig_and_error(8, 211, rx_amp_log_c, rx_amp_log - rx_amp_log_c, 'Amp Est', [1 n -1.5 1.5]) + phi_log_diff = rx_phi_log - rx_phi_log_c; + phi_log_diff(find(phi_log_diff > pi)) -= 2*pi; + phi_log_diff(find(phi_log_diff < -pi)) += 2*pi; + stem_sig_and_error(8, 212, rx_phi_log_c, phi_log_diff, 'Phase Est', [1 n -4 4]) + stem_sig_and_error(9, 211, real(rx_symb_log_c), real(rx_symb_log - rx_symb_log_c), 'rx symb re', [1 n -1.5 1.5]) + stem_sig_and_error(9, 212, imag(rx_symb_log_c), imag(rx_symb_log - rx_symb_log_c), 'rx symb im', [1 n -1.5 1.5]) + + stem_sig_and_error(10, 111, rx_bits_log_c, rx_bits_log - rx_bits_log_c, 'rx bits', [1 length(rx_bits_log) -1.5 1.5]) + stem_sig_and_error(11, 111, f_est_log_c - Fcentre - foff, f_est_log - f_est_log_c, 'f est', [1 length(f_est_log) -5 5]) + stem_sig_and_error(12, 111, rx_timing_log_c, rx_timing_log_c - rx_timing_log, 'rx timing', [1 length(rx_timing_log) -M M]) + + check(tx_bits_log, tx_bits_log_c, 'tx_bits'); + check(tx_symb_log, tx_symb_log_c, 'tx_symb'); + check(tx_fdm_frame_log, tx_fdm_frame_log_c, 'tx_fdm_frame',0.01); + check(ch_fdm_frame_log, ch_fdm_frame_log_c, 'ch_fdm_frame',0.01); + %check(rx_fdm_frame_bb_log, rx_fdm_frame_bb_log_c, 'rx_fdm_frame_bb', 0.01); + + check(ch_symb_log, ch_symb_log_c, 'ch_symb',0.05); + %check(ct_symb_ff_log, ct_symb_ff_log_c, 'ct_symb_ff',0.01); + check(rx_amp_log, rx_amp_log_c, 'rx_amp_log',0.01); + check(phi_log_diff, zeros(length(phi_log_diff), Nc*Nd), 'rx_phi_log',0.1); + check(rx_symb_log, rx_symb_log_c, 'rx_symb',0.01); + check(rx_timing_log, rx_timing_log_c, 'rx_timing',0.005); + check(rx_bits_log, rx_bits_log_c, 'rx_bits'); + check(f_est_log, f_est_log_c, 'f_est'); + check(sig_rms_log, sig_rms_log_c, 'sig_rms'); + check(noise_rms_log, noise_rms_log_c, 'noise_rms'); + + +else + + papr = max(tx_fdm_frame_log.*conj(tx_fdm_frame_log)) / mean(tx_fdm_frame_log.*conj(tx_fdm_frame_log)); + papr_dB = 10*log10(papr); + printf("av tx pwr: %4.2f PAPR: %4.2f av rx pwr: %4.2f\n", var(tx_fdm_frame_log), papr_dB, var(ch_fdm_frame_log)); + + % some other useful plots + + figure(1) + clf + subplot(211) + plot(real(tx_fdm_frame_log)) + title('tx fdm real'); + subplot(212) + plot(imag(tx_fdm_frame_log)) + title('tx fdm imag'); + + figure(2) + clf + spec = 20*log10(abs(fft(tx_fdm_frame_log))); + l = length(spec); + plot((Fs/l)*(1:l), spec) + axis([1 Fs/2 0 max(spec)]); + title('tx spectrum'); + ylabel('Amplitude (dB)') + xlabel('Frequency (Hz)') + grid; + + figure(3) + clf; + % plot combined signals to show diversity gains + combined = rx_symb_log(:,1:Nc); + for d=2:Nd + combined += rx_symb_log(:, (d-1)*Nc+1:d*Nc); + end + plot(combined*exp(j*pi/4)/sqrt(Nd),'+') + title('Scatter'); + ymax = abs(max(max(combined))); + axis([-ymax ymax -ymax ymax]) + + figure(4) + clf; + subplot(211) + plot(rx_phi_log) + subplot(212) + plot(rx_amp_log) + + figure(5) + clf; + subplot(211) + plot(rx_timing_log) + title('rx timing'); + subplot(212) + stem(ratio_log) + title('Sync ratio'); + + figure(6) + clf; + subplot(211) + stem(nerr_log) + title('Bit Errors'); + subplot(212) + plot(noise_rms_filt_log,'r', sig_rms_log,'g'); + title('Est rms signal and noise') + + figure(7); + clf; + subplot(211) + plot(foff_log,';freq offset;'); + hold on; + plot(f_est_log - Fcentre,'g;freq offset est;'); + hold off; + title('freq offset'); + legend("boxoff"); + subplot(212) + plot(foff_log(1:length(f_est_log)) - f_est_log + Fcentre) + title('freq offset estimation error'); + + figure(8) + clf + h = freqz(b,a,Fs/2); + plot(20*log10(abs(h))) + axis([1 Fs/2 -20 0]) + grid + title('SSB tx filter') + + figure(9) + clf + plot(error_positions_hist) + title('histogram of bit errors') + + +end + + +% function to write C header file of noise samples so C version gives +% extactly the same results + +function write_noise_file(uvnoise_log) + + m = length(uvnoise_log); + + filename = sprintf("../unittest/noise_samples.h"); + f=fopen(filename,"wt"); + fprintf(f,"/* unit variance complex noise samples */\n\n"); + fprintf(f,"/* Generated by write_noise_file() Octave function */\n\n"); + fprintf(f,"COMP noise[]={\n"); + for r=1:m + if r < m + fprintf(f, " {%f,%f},\n", real(uvnoise_log(r)), imag(uvnoise_log(r))); + else + fprintf(f, " {%f,%f}\n};", real(uvnoise_log(r)), imag(uvnoise_log(r))); + end + end + + fclose(f); +endfunction + + +% function to write float fading samples for use by C programs + +function write_noise_file(raw_file_name, Fs, len_samples) + [spread spread_2ms hf_gain] = init_hf_model(Fs, len_samples); + hf_gain + % interleave real imag samples + + inter = zeros(1,len_samples*4); + inter(1:4) = hf_gain; + for i=1:len_samples + inter(i*4+1) = real(spread(i)); + inter(i*4+2) = imag(spread(i)); + inter(i*4+3) = real(spread_2ms(i)); + inter(i*4+4) = imag(spread_2ms(i)); + end + f = fopen(raw_file_name,"wb"); + fwrite(f, inter, "float32"); + fclose(f); +endfunction diff --git a/codec2/branches/0.7/octave/telem_upload.py b/codec2/branches/0.7/octave/telem_upload.py new file mode 100644 index 00000000..ada35a75 --- /dev/null +++ b/codec2/branches/0.7/octave/telem_upload.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# Horus Binary (and oldschool) Telemetry Uploader +# +# Mark Jessop 2015-12-31 +# +# +# This script takes either a hex representation of the binary payload, or +# a 'classic' ASCII sentence, and uploads it to Habitat. +# +# Currently this script tells the two apart by looking for 'HORUS' at the start +# of the argument to determine if it's an ASCII sentence. +# +# It's designed to be called from fsk_horus_stream.m, and is tailored for it's output. +# +# Dependencies: +# - Python 2.7 (Will probably break in Python 3) +# - crcmod (pip install crcmod) +# + +import time, struct, json, socket, httplib, crcmod, argparse, sys +from base64 import b64encode +from hashlib import sha256 +from datetime import datetime + +def crc16_ccitt(data): + """ + Calculate the CRC16 CCITT checksum of *data*. + + (CRC16 CCITT: start 0xFFFF, poly 0x1021) + """ + crc16 = crcmod.predefined.mkCrcFun('crc-ccitt-false') + return crc16(data) + +# Binary packet format, from https://github.com/darksidelemm/PicoHorusBinary/tree/master/PicoPayloadGPS +# struct TBinaryPacket +# { +# uint8_t PayloadID; +# uint16_t Counter; +# uint8_t Hours; +# uint8_t Minutes; +# uint8_t Seconds; +# float Latitude; +# float Longitude; +# uint16_t Altitude; +# uint8_t Speed; // Speed in Knots (1-255 knots) +# uint8_t Sats; +# int8_t Temp; // Twos Complement Temp value. +# uint8_t BattVoltage; // 0 = 0.5v, 255 = 2.0V, linear steps in-between. +# uint16_t Checksum; // CRC16-CCITT Checksum. +# }; // __attribute__ ((packed)); + +def decode_horus_binary_telemetry(payload): + + horus_format_struct = " hpa_clip)) = hpa_clip; + + papr = max(tx_fdm.*conj(tx_fdm)) / mean(tx_fdm.*conj(tx_fdm)); + papr_dB = 10*log10(papr); + printf("PAPR: %4.2f dB\n", papr_dB); + + Ascale = 2000; + figure(1); + clf; + plot(Ascale*tx_fdm(1:8000)) + + ftx=fopen(tx_filename,"wb"); fwrite(ftx, Ascale*real(tx_fdm), "short"); fclose(ftx); + +endfunction + + +function rate_Fs_rx(rx_filename) + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.framesize = 160; + sim_in.Nc = 4; + sim_in.Rs = 50; + sim_in.Ns = 4; + sim_in.Np = 4; + sim_in.Nchip = 1; + sim_in.ldpc_code_rate = 1; + sim_in.ldpc_code = 0; + + sim_in.Ntrials = 10; + sim_in.Esvec = 40; + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 0; + sim_in.modulation = 'qpsk'; + + sim_in = symbol_rate_init(sim_in); + + prev_sym_tx = sim_in.prev_sym_tx; + prev_sym_rx = sim_in.prev_sym_rx; + code_param = sim_in.code_param; + tx_bits_buf = sim_in.tx_bits_buf; + framesize = sim_in.framesize; + rate = sim_in.ldpc_code_rate; + Ntrials = sim_in.Ntrials; + Rs = sim_in.Rs; + Fs = sim_in.Fs; + Nc = sim_in.Nc; + Nsymbrowpilot = sim_in.Nsymbrowpilot; + pilot = sim_in.pilot; + Ns = sim_in.Ns; + Npilotsframe = sim_in.Npilotsframe; + + M = Fs/Rs; + + EsNodB = sim_in.Esvec(1); + EsNo = 10^(EsNodB/10); + + phi_log = []; amp_log = []; EsNo__log = []; + rx_symb_log = []; av_tx_pwr = []; + Terrs = Tbits = 0; + errors_log = []; Nerrs_log = []; + ldpc_Nerrs_log = []; ldpc_errors_log = []; + Ferrsldpc = Terrsldpc = Tbitsldpc = 0; + + rn_coeff = gen_rn_coeffs(0.5, 1/Fs, Rs, 6, M); + + tx_bits = round(rand(1,framesize*rate)); + + % read from disk + + Ascale = 2000; + frx=fopen(rx_filename,"rb"); rx_fdm = fread(frx, "short")/Ascale; fclose(frx); + + rx_fdm=sqrt(2)*rx_fdm; + + if 0 + % optionally add AWGN noise for testing calibration of Es//No measurement + + snr_3000Hz_dB = -9; + snr_4000Hz_lin = 10 ^ (snr_3000Hz_dB/10); + snr_4000Hz_lin *= (3000/4000); + variance = var(rx_fdm)/snr_4000Hz_lin; + rx_fdm += sqrt(variance)*randn(length(rx_fdm),1); + end + + figure(1) + plot(rx_fdm(800:1200)); + + % freq offset estimation + + printf("Freq offset and coarse timing est...\n"); + [f_max max_s_Fs] = test_freq_off_est(rx_filename, 1,5*6400); + f_max = 0; max_s_Fs = 4; + max_s = floor(max_s_Fs/M + 6); + + printf("Downconverting...\n"); + + [m n] = size(rx_fdm); + rx_symb = zeros(m,Nc); + Fc = 1500; + for c=1:Nc + freq(c) = exp(-j*2*pi*(f_max + Fc - c*Rs*1.5)/Fs); + end + phase_rx = ones(1,Nc); + rx_bb = zeros(m,Nc); + + for c=1:Nc + for i=1:m + phase_rx(c) = phase_rx(c) * freq(c); + rx_bb(i,c) = rx_fdm(i)*phase_rx(c); + end + end + + printf("Filtering...\n"); + for c=1:Nc + rx_filt(:,c) = filter(rn_coeff, 1, rx_bb(:,c)); + end + + %subplot(211); + %plot(real(rx_filt(1:10*M,9))); + %subplot(212); + %plot(imag(rx_filt(1:10*M,9))); + + % Fine timing estimation and decimation to symbol rate Rs. Break rx + % signal into ft sample blocks. If clock offset is 1000ppm, + % that's one more/less sample over Ft samples at Fs=8000 Hz. + + printf("Fine timing estimation....\n"); + ft = M*10; + [nsam m] = size(rx_filt); + rx_symb_buf = []; rx_timing_log = []; + + for st=1:ft:floor(nsam/ft - 1)*ft + % fine timing and decimation + + env = zeros(ft,1); + for c=1:Nc + env = env + abs(rx_filt(st:st+ft-1,c)); + end + + % The envelope has a frequency component at the symbol rate. The + % phase of this frequency component indicates the timing. So work out + % single DFT at frequency 2*pi/M + + x = exp(-j*2*pi*(0:ft-1)/M) * env; + + norm_rx_timing = angle(x)/(2*pi); + %norm_rx_timing = -0.4; + if norm_rx_timing < 0 + rx_timing = -floor(norm_rx_timing*M+0.5) + M; + else + rx_timing = -floor(norm_rx_timing*M+0.5) + 2*M; + end + rx_timing_log = [rx_timing_log norm_rx_timing]; + + % printf("%d %d\n", st+rx_timing, st+rx_timing+ft-1); + rx_symb_buf = [rx_symb_buf; rx_filt(st+rx_timing:M:st+rx_timing+ft-1,:)]; + end + + figure(2) + clf; + plot(rx_timing_log) + axis([1 length(rx_timing_log) -0.5 0.5 ]) + title('fine timing') + + printf("Symbol rate demodulation....\n"); + phase_off = 1; + Ntrials = floor((nsam/M)/Nsymbrowpilot) - 2; + %max_s = 6; + + for nn=1:Ntrials + + s_ch = rx_symb_buf((nn-1)*Nsymbrowpilot+max_s:nn*Nsymbrowpilot+max_s-1,:); + [rx_symb rx_bits rx_symb_linear amp_linear amp_ phi_ EsNo_ prev_sym_rx sim_in] = symbol_rate_rx(sim_in, s_ch, prev_sym_rx); + + rx_symb_log = [rx_symb_log rx_symb_linear]; + phi_log = [phi_log; phi_]; + amp_log = [amp_log; amp_]; + + if nn > 1 + EsNo__log = [EsNo__log EsNo_]; + + % Measure BER + + error_positions = xor(rx_bits(1:framesize*rate), tx_bits(1:framesize*rate)); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += framesize*rate; + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + + if sim_in.ldpc_code + % LDPC decode + + detected_data = ldpc_dec(code_param, sim_in.max_iterations, sim_in.demod_type, sim_in.decoder_type, ... + rx_symb_linear, min(100,EsNo_), amp_linear); + error_positions = xor(detected_data(1:framesize*rate), tx_bits(1:framesize*rate) ); + Nerrs = sum(error_positions); + ldpc_Nerrs_log = [ldpc_Nerrs_log Nerrs]; + ldpc_errors_log = [ldpc_errors_log error_positions]; + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + end + end + end + + EsNo_av = mean(10*log10(EsNo__log)); + printf("EsNo est (dB): %3.1f SNR est: %3.2f Terrs: %d BER %4.2f QPSK BER theory %4.2f av_tx_pwr: %3.2f", + EsNo_av, mean(EsNo_to_SNR(10*log10(EsNo__log))), + Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + if sim_in.ldpc_code + printf("\n LDPC: Terrs: %d BER: %4.2f Ferrs: %d FER: %4.2f\n", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/Ntrials); + end + + figure(3); + clf; + scat = rx_symb_log .* exp(j*pi/4); + scat = scat((framesize):length(scat)); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + figure(4) + clf + subplot(211) + stem(Nerrs_log) + axis([0 Ntrials+1 0 max(Nerrs_log)+1]) + title('Uncoded Errors/Frame'); + if sim_in.ldpc_code + subplot(212) + stem(ldpc_Nerrs_log) + axis([0 Ntrials+1 0 max(ldpc_Nerrs_log)+1]) + title('Coded Errors/Frame'); + end + + figure(5) + clf + [m1 n1] = size(phi_log); + phi_x = []; + phi_x_counter = 1; + p = Ns; + for r=1:m1 + if p == Ns + phi_x_counter++; + p = 0; + end + p++; + phi_x = [phi_x phi_x_counter++]; + end + + subplot(211) + plot(phi_x, phi_log(:,1),'r+;Estimated HF channel phase;') + ylabel('Phase (rads)'); + legend('boxoff'); + + subplot(212) + plot(phi_x, amp_log(:,1),'r+;Estimated HF channel amp;') + ylabel('Amplitude'); + xlabel('Time (symbols)'); + legend('boxoff'); + + figure(6); + clf + plot(EsNo_to_SNR(10*log10(EsNo__log))); + title('SNR est (dB)') + + fep=fopen("errors_450.bin","wb"); fwrite(fep, ldpc_errors_log, "short"); fclose(fep); + +endfunction + + + + +function snr = EsNo_to_SNR(EsNo) + snr = interp1([20 11.8 9.0 6.7 4.9 3.3 -10], [ 3 3 0 -3 -6 -9 -9], EsNo); +endfunction + + +function gen_test_bits() + sim_in = standard_init(); + framesize = 32*10; + tx_bits = round(rand(1,framesize)); + test_bits_coh_file(tx_bits); +endfunction + + + + +% Start simulations --------------------------------------- + +more off; +%close all; +%test_curves(); +test_single(); +%rate_Fs_tx("tx_zero.raw"); +%rate_Fs_tx("tx.raw"); +%rate_Fs_rx("tx_-4dB.wav") +%rate_Fs_rx("tx.raw") +%gen_test_bits(); + diff --git a/codec2/branches/0.7/octave/test_cohpsk_ch.m b/codec2/branches/0.7/octave/test_cohpsk_ch.m new file mode 100644 index 00000000..19634ddf --- /dev/null +++ b/codec2/branches/0.7/octave/test_cohpsk_ch.m @@ -0,0 +1,21 @@ +% test_cohpsk_ch.m +% David Rowe May 2015 +% +% Plot outputs from test_coh_psk_ch.c + +Nc=7; Nd=2; + +load ../build_linux/src/test_cohpsk_ch_out.txt + +figure(3) +clf; + +% plot combined signals to show diversity gains + +combined = rx_symb_log_c(:,1:Nc); +for d=2:Nd + combined += rx_symb_log_c(:, (d-1)*Nc+1:d*Nc); +end +plot(combined*exp(j*pi/4)/sqrt(Nd),'+') +title('Scatter'); +axis([-2 2 -2 2]) diff --git a/codec2/branches/0.7/octave/test_dqpsk.m b/codec2/branches/0.7/octave/test_dqpsk.m new file mode 100644 index 00000000..9db9d121 --- /dev/null +++ b/codec2/branches/0.7/octave/test_dqpsk.m @@ -0,0 +1,394 @@ +% test_dqpsk.m +% David Rowe March 2014 +% +% Single sample/symbol DQPSK modem simulation to test modulating modem +% tx power based on speech energy. + +1; + +% main test function + +function sim_out = ber_test(sim_in) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_phase_only = sim_in.hf_phase_only; + hf_mag_only = sim_in.hf_mag_only; + Nc = sim_in.Nc; + symbol_amp = sim_in.symbol_amp; + + bps = 2; + Nsymb = framesize/bps; + for k=1:Nc + prev_sym_tx(k) = qpsk_mod([0 0]); + prev_sym_rx(k) = qpsk_mod([0 0]); + end + + rate = 1; + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + noise_log = []; + sim_out.errors_log = []; + + % init HF channel + + hf_n = 1; + hf_angle_log = []; + hf_fading = ones(1,Nsymb); % default input for ldpc dec + hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface + + sim_out.errors_log = []; + sim_out.Nerrs = []; + sim_out.snr_log = []; + sim_out.hf_model_pwr = []; + + symbol_amp_index = 1; + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize*rate ) ); + + % modulate -------------------------------------------- + + s = zeros(1, Nsymb); + for i=1:Nc:Nsymb + for k=1:Nc + tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1))); + tx_symb *= prev_sym_tx(k); + prev_sym_tx(k) = tx_symb; + s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb; + end + end + s_ch = s; + symbol_amp_index++; + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this is + % effectively under samples at Rs, I dont think this + % matters. Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + if Nsymb/Nc != floor(Nsymb/Nc) + printf("Error: Nsymb/Nc must be an integrer\n") + return; + end + + % arrange symbols in Nsymb/Nc by Nc matrix + + for i=1:Nc:Nsymb + + % Determine HF channel at each carrier for this symbol + + for k=1:Nc + hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n)); + hf_fading(i+k-1) = abs(hf_model(hf_n, k)); + if hf_mag_only + s_ch(i+k-1) *= abs(hf_model(hf_n, k)); + else + s_ch(i+k-1) *= hf_model(hf_n, k); + end + end + hf_n++; + end + end + + tx_symb_log = [tx_symb_log s_ch]; + + % "genie" SNR estimate + + snr = (s_ch*s_ch')/(Nsymb*variance); + sim_out.snr_log = [sim_out.snr_log snr]; + sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(hf_fading.^2)]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + noise_log = [noise_log noise]; + + % organise into carriers to apply frequency and phase offset + + for i=1:Nc:Nsymb + for k=1:Nc + s_ch(i+k-1) = s_ch(i+k-1)*exp(j*phase_offset) + noise(i+k-1); + end + phase_offset += w_offset; + end + + % de-modulate + + rx_bits = zeros(1, framesize); + for i=1:Nc:Nsymb + for k=1:Nc + rx_symb = s_ch(i+k-1); + tmp = rx_symb; + rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k))); + prev_sym_rx(k) = tmp; + rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb); + rx_symb_log = [rx_symb_log rx_symb]; + end + end + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + sim_out.Nerrs = [sim_out.Nerrs Nerrs]; + Terrs += Nerrs; + Tbits += length(tx_bits); + + sim_out.errors_log = [sim_out.errors_log error_positions]; + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits); + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + figure(3); + clf; + y = 1:Rs*2; + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + mesh(x,y,EsNodBSurface); + grid + title('HF Channel Es/No'); + + if 0 + figure(4); + clf; + subplot(211) + plot(y,abs(hf_model(y,1))) + title('HF Channel Carrier 1 Mag'); + subplot(212) + plot(y,angle(hf_model(y,1))) + title('HF Channel Carrier 1 Phase'); + end + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5:15; + sim_in.Ntrials = 100; + sim_in.framesize = 64; + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_phase_only = 0; + sim_in.hf_mag_only = 0; +endfunction + +function awgn_hf_ber_curves() + sim_in = standard_init(); + + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + dpsk_awgn = ber_test(sim_in); + sim_in.hf_sim = 1; + dpsk_hf = ber_test(sim_in); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;') + semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;') + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +end + +sim_in = standard_init(); + +% energy file sampled every 10ms + +load ../src/ve9qrp.txt +pdB=10*log10(ve9qrp); +for i=1:length(pdB) + if pdB(i) < 0 + pdB(i) = 0; + end +end + +% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted + +pdB = pdB(4:4:length(pdB)); + +% Use linear mapping function in dB domain to map to symbol power + +power_map_x = [ 0 20 24 40 50 ]; +power_map_y = [-6 -6 0 6 6]; +mapped_pdB = interp1(power_map_x, power_map_y, pdB); + +%sim_in.symbol_amp = 10 .^ (mapped_pdB/20); +sim_in.symbol_amp = ones(1,length(pdB)); +sim_in.plot_scatter = 1; +sim_in.verbose = 2; +sim_in.hf_sim = 1; +sim_in.Esvec = 10; +sim_in.Ntrials = 400; + +dqpsk_pwr_hf = ber_test(sim_in); + +% note: need way to test that power is aligned with speech + +figure(4) +clf; +plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials)); +hold on; +plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r'); +hold off; + +figure(5) +clf; + +s = load_raw("../raw/ve9qrp.raw"); +M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window +plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M)) +hold on; +plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r'); +hold off; +axis([1 sim_in.Ntrials*M -3E4 3E4]); + +figure(6) +clf; +plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);'); +hold on; +plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);'); +plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);'); + +ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize; +ber_clip = ber; +ber_clip(find(ber > 0.2)) = 0.2; +plot((1:sim_in.Ntrials)*M, -20+100*ber_clip,'k;BER (0-20%);'); +hold off; +axis([1 sim_in.Ntrials*M -20 20]) + +fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep); +fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber); diff --git a/codec2/branches/0.7/octave/test_dqpsk2.m b/codec2/branches/0.7/octave/test_dqpsk2.m new file mode 100644 index 00000000..d421d624 --- /dev/null +++ b/codec2/branches/0.7/octave/test_dqpsk2.m @@ -0,0 +1,465 @@ +% test_dqpsk2.m +% David Rowe April 2014 +% +% DQPSK modem simulation inclduing filtering to test modulating modem +% tx power based on speech energy. Unlike test_dpsk runs at sample +% rate Fs. + +1; + +% main test function + +function sim_out = ber_test(sim_in) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + Nhfdelay = floor(sim_in.hf_delay_ms*Fs/1000); + Nc = sim_in.Nc; + symbol_amp = sim_in.symbol_amp; + + bps = 2; + Nsymb = framesize/bps; + for k=1:Nc + prev_sym_tx(k) = qpsk_mod([0 0]); + prev_sym_rx(k) = qpsk_mod([0 0]); + end + + % design root nyquist (root raised cosine) filter and init tx and rx filter states + + alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs; + if floor(Fs/Rs) != Fs/Rs + printf("oversampling ratio must be an integer\n"); + return; + end + hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M); + Nfilter = length(hrn); + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up. Transpose for convenience + + spread = transpose(spread(1000:length(spread))); + spread_2ms = transpose(spread_2ms(1000:length(spread_2ms))); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = Fs/(Rs*EsNo); + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + noise_log = []; + sim_out.errors_log = []; + sim_out.tx_baseband_log = []; + sim_out.rx_filt_log = []; + symbol_amp_index = 1; + + % init filter memories and LOs + + tx_filter_memory = zeros(Nc, Nfilter); + rx_filter_memory = zeros(Nc, Nfilter); + s_delay_line_filt = zeros(Nc, Nfiltsym); + phase_tx = ones(1,Nc); + phase_rx = ones(1,Nc); + Fcentre = 1500; Fsep = (1+alpha)*Rs; + freq = Fcentre + Fsep*((-Nc/2+0.5):(Nc/2-0.5)); + freq = exp(j*freq*2*pi/Fs); + + % init HF channel + + sc = 1; hf_n = 1; + hf_sim_delay_line = zeros(1,M+Nhfdelay); + freq_sample_hz = Fcentre + ((Fsep*(-Nc/2)):50:(Fsep*(Nc/2))); + freq_sample_rads = (2*pi/Fs)*freq_sample_hz; + hf_model = ones(Ntrials*Nsymb/Nc, length(freq_sample_rads)); % defaults for plotting surface + + % bunch of outputs we log for graphing + + sim_out.errors_log = []; + sim_out.Nerrs = []; + sim_out.snr_log = []; + sim_out.hf_model_pwr = []; + sim_out.tx_fdm_log = []; + C_log = []; + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize ) ); + + % modulate -------------------------------------------- + + s = zeros(1, Nsymb); + for i=1:Nc:Nsymb + for k=1:Nc + tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1))); + s_qpsk(i+k-1) = tx_symb; + tx_symb *= prev_sym_tx(k); + prev_sym_tx(k) = tx_symb; + s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb; + end + end + symbol_amp_index++; + s_ch = s; + + % Now we start processing frame Nc symbols at a time to model parallel carriers + + tx_fdm_sym_log = []; + for i=1:Nc:Nsymb + + % Delay tx symbols to match delay due to filters. qpsk + % (rather than dqpsk) symbols used for convenience as + % it's easy to shift symbols than pairs of bits + + s_delay_line_filt(:,1:Nfiltsym-1) = s_delay_line_filt(:,2:Nfiltsym); + s_delay_line_filt(:,Nfiltsym) = s_qpsk(i:i+Nc-1); + s_qpsk(i:i+Nc-1) = s_delay_line_filt(:,1); + for k=1:Nc + tx_bits(2*(i-1+k-1)+1:2*(i+k-1)) = qpsk_demod(s_qpsk(i+k-1)); + end + + % tx filter + + tx_baseband = zeros(Nc,M); + + % tx filter each symbol, generate M filtered output samples for each symbol. + % Efficient polyphase filter techniques used as tx_filter_memory is sparse + + tx_filter_memory(:,Nfilter) = s(i:i+Nc-1); + + for k=1:M + tx_baseband(:,k) = M*tx_filter_memory(:,M:M:Nfilter) * hrn(M-k+1:M:Nfilter)'; + end + tx_filter_memory(:,1:Nfilter-M) = tx_filter_memory(:,M+1:Nfilter); + tx_filter_memory(:,Nfilter-M+1:Nfilter) = zeros(Nc,M); + + sim_out.tx_baseband_log = [sim_out.tx_baseband_log tx_baseband]; + + % upconvert + + tx_fdm = zeros(1,M); + + for c=1:Nc + for k=1:M + phase_tx(c) = phase_tx(c) * freq(c); + tx_fdm(k) = tx_fdm(k) + tx_baseband(c,k)*phase_tx(c); + end + end + + sim_out.tx_fdm_log = [sim_out.tx_fdm_log tx_fdm]; + + % HF channel + + if hf_sim + hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay); + hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_fdm; + + tx_fdm = tx_fdm.*spread(sc:sc+M-1) + hf_sim_delay_line(1:M).*spread_2ms(sc:sc+M-1); + tx_fdm *= hf_gain; + + % sample HF channel spectrum in middle of this symbol for plotting + + hf_model(hf_n,:) = hf_gain*(spread(sc+M/2) + exp(-j*freq_sample_rads*Nhfdelay)*spread_2ms(sc+M/2)); + + sc += M; + hf_n++; + end + + tx_fdm_sym_log = [tx_fdm_sym_log tx_fdm ]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,M) + j*randn(1,M)); + noise_log = [noise_log noise]; + + % apply frequency and phase offset and noise + + for k=1:M + rx_fdm(k) = tx_fdm(k)*exp(j*phase_offset) + noise(k); + phase_offset += w_offset; + end + + % downconvert + + rx_baseband = zeros(Nc,M); + for c=1:Nc + for k=1:M + phase_rx(c) = phase_rx(c) * freq(c); + rx_baseband(c,k) = rx_fdm(k)*phase_rx(c)'; + end + end + + % rx filter + + rx_filter_memory(:,Nfilter-M+1:Nfilter) = rx_baseband; + rx_filt = rx_filter_memory * hrn'; + rx_filter_memory(:,1:Nfilter-M) = rx_filter_memory(:,1+M:Nfilter); + sim_out.rx_filt_log = [sim_out.rx_filt_log rx_filt]; + + s_ch(i:i+Nc-1) = rx_filt; + end + + % est HF model power for entire code frame (which could be several symbols) + + if hf_sim + frame_hf_model = reshape(hf_model(hf_n-Nsymb/Nc:hf_n-1,:),1,(Nsymb/Nc)*length(freq_sample_hz)); + sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(abs(frame_hf_model).^2)]; + else + sim_out.hf_model_pwr = [sim_out.hf_model_pwr 1]; + end + + % "genie" SNR estimate + + snr = (tx_fdm_sym_log*tx_fdm_sym_log')/(M*variance); + sim_out.snr_log = [sim_out.snr_log snr]; + + % de-modulate + + rx_bits = zeros(1, framesize); + for i=1:Nc:Nsymb + for k=1:Nc + rx_symb = s_ch(i+k-1); + tmp = rx_symb; + rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k))); + prev_sym_rx(k) = tmp; + rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb); + rx_symb_log = [rx_symb_log rx_symb]; + end + end + + % ignore data until we have enough frames to fill filter memory + % then count errors + + if nn > ceil(Nfiltsym/(Nsymb/Nc)) + error_positions = xor(rx_bits, tx_bits); + sim_out.errors_log = [sim_out.errors_log error_positions]; + Nerrs = sum(error_positions); + sim_out.Nerrs = [sim_out.Nerrs Nerrs]; + Terrs += Nerrs; + Tbits += length(tx_bits); + end + + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits); + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, var(sim_out.tx_fdm_log), var(noise_log), + var(sim_out.tx_fdm_log)/(Nc*Rs), var(noise_log)/Fs, (var(sim_out.tx_fdm_log)/(Nc*Rs))/(var(noise_log)/Fs)); + end + end + + Ebvec = Esvec - 10*log10(bps); + + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log(Nfiltsym*Nc:length(rx_symb_log)) .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + figure(3); + clf; + y = 1:Rs*2; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) + EsNodB; + mesh(1:length(freq_sample_hz),y,EsNodBSurface); + grid + title('HF Channel Es/No'); + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5:15; + sim_in.Ntrials = 100; + sim_in.framesize = 64; + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_phase_only = 0; + sim_in.hf_mag_only = 0; +endfunction + +function awgn_hf_ber_curves() + sim_in = standard_init(); + + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + dpsk_awgn = ber_test(sim_in); + sim_in.hf_sim = 1; + dpsk_hf = ber_test(sim_in); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;') + semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;') + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +end + +sim_in = standard_init(); + +% energy file sampled every 10ms + +load ../src/ve9qrp.txt +pdB=10*log10(ve9qrp); +for i=1:length(pdB) + if pdB(i) < 0 + pdB(i) = 0; + end +end + +% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted + +pdB = pdB(4:4:length(pdB)); + +% Use linear mapping function in dB domain to map to symbol power + +%power_map_x = [ 0 20 24 40 50 ]; +%power_map_y = [--6 -6 0 6 6]; +power_map_x = [ 0 50 ]; +power_map_y = [ -15 12]; +mapped_pdB = interp1(power_map_x, power_map_y, pdB); + +sim_in.symbol_amp = 10 .^ (mapped_pdB/20); +%sim_in.symbol_amp = ones(1,length(pdB)); +sim_in.plot_scatter = 1; +sim_in.verbose = 2; +sim_in.hf_delay_ms = 2; +sim_in.hf_sim = 1; +sim_in.Esvec = 10; +sim_in.Ntrials = 400; + +dqpsk_pwr_hf = ber_test(sim_in); + +% note: need way to test that power is aligned with speech + +figure(4) +clf; +plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials)); +hold on; +plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r'); +hold off; + +figure(5) +clf; +s = load_raw("../raw/ve9qrp.raw"); +M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window +subplot(211) +plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M)) +hold on; +plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r'); +hold off; +axis([1 sim_in.Ntrials*M -3E4 3E4]); +subplot(212) +plot(real(dqpsk_pwr_hf.tx_fdm_log)); + + +figure(6) +clf; +plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);'); +hold on; +plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);'); +plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);'); + +ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize; +ber_clip = ber; +ber_clip(find(ber > 0.2)) = 0.2; +plot((1:length(ber_clip))*M, -20+100*ber_clip,'k;BER (0-20%);'); +hold off; +axis([1 sim_in.Ntrials*M -20 20]) + +fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep); +fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber); diff --git a/codec2/branches/0.7/octave/test_dsss.m b/codec2/branches/0.7/octave/test_dsss.m new file mode 100644 index 00000000..78ed90bc --- /dev/null +++ b/codec2/branches/0.7/octave/test_dsss.m @@ -0,0 +1,410 @@ +% test_dsss.m +% David Rowe Oct 2014 +% + +% Simulation to test FDM QPSK combined with DSSS. A low rate Codec +% (e.g. 450 bit/s) is transmitted on Nc=4 FDM carriers. This same +% information is repeated Nchip=4 times on bocks of carriers that are +% delayed by up to Rs symbols. It's like spread spectrum with a +% spreading code of 1111. Turns out this goes a long way to +% converting a fading channel into an AWGN one. Good scatter diagram +% and BER curve results. Disadvantage is more bandwidth is required. + +% When output error files used to simulate codec provided a few dB +% drop to 1dB SNR for intelligable speech for 450 codec combined with +% DSSS compared with legacy 1600 bit/s mode that has FEC. Improvement +% not as great as hoped as 1600 codec can cope with higher BER. + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + Nchip = sim_in.Nchip; + + bps = 2; + Nc = Nsymb = framesize/bps; + prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc*Nchip); + prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc*Nchip); + + tx_bits_buf = zeros(1,2*framesize); + rx_bits_buf = zeros(1,2*framesize); + rx_symb_buf = zeros(1,2*Nsymb); + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + noise_log = []; + errors_log = []; + Nerrs_log = []; + + % init HF channel + + hf_n = 1; + + % simulation starts here----------------------------------- + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize) ); + + % modulate -------------------------------------------- + + tx_symb=zeros(1,Nc*Nchip); + + for i=1:Nc + tx_symb(i) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + end + + % Optionally copy to other carriers (spreading) + + for i=Nc+1:Nc:Nc*Nchip + tx_symb(i:i+Nc-1) = tx_symb(1:Nc); + end + + % Optionally DQPSK encode + + if strcmp(modulation,'dqpsk') + for i=1:Nc*Nchip + tx_symb(i) *= prev_sym_tx(i); + prev_sym_tx(i) = tx_symb(i); + end + end + + s_ch = tx_symb/sqrt(Nchip); + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + hf_model(hf_n, :) = zeros(1,Nc); + + for i=1:Nchip + time_shift = floor(i*Rs/4); + for k=1:Nc + ahf_model = hf_gain*(spread(hf_n+time_shift) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n+time_shift)); + if hf_mag_only + s_ch((i-1)*Nc+k) *= abs(ahf_model); + else + s_ch((i-1)*Nc+k) *= ahf_model; + end + hf_model(hf_n, k) += ahf_model/Nchip; + end + end + hf_n++; + end + + tx_symb_log = [tx_symb_log s_ch]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb*Nchip) + j*randn(1,Nsymb*Nchip)); + noise_log = [noise_log noise]; + + s_ch = s_ch + noise; + + % de-modulate + + for i=1:Nc*Nchip + rx_symb(i) = s_ch(i); + if strcmp(modulation,'dqpsk') + tmp = rx_symb(i); + rx_symb(i) *= conj(prev_sym_rx(i)/abs(prev_sym_rx(i))); + prev_sym_rx(i) = tmp; + end + end + + % de-spread + + for i=Nc+1:Nc:Nchip*Nc + rx_symb(1:Nc) = rx_symb(1:Nc) + rx_symb(i:i+Nc-1); + end + + % demodulate + + rx_bits = zeros(1, framesize); + for i=1:Nc + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb(i)); + end + rx_symb_log = [rx_symb_log rx_symb(1:Nc)]; + + % Measure BER + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + av_tx_pwr = (tx_symb_log * tx_symb_log')/length(tx_symb_log); + + printf("EsNo (dB): %f Terrs: %d BER %4.2f QPSK BER theory %4.2f av_tx_pwr: %3.2f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + if hf_sim + figure(3); + clf; + + y = 1:(hf_n-1); + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + mesh(x,y,EsNodBSurface); + grid + axis([1 Nc 1 Rs*5 -5 15]) + title('HF Channel Es/No'); + + if verbose + av_hf_pwr = sum(abs(hf_model(y)).^2)/(hf_n-1); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, hf_n-1); + end + end + + figure(4) + clf + stem(Nerrs_log) + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.framesize = 8; + sim_in.Rs = 50; + sim_in.Nc = 4; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; + + sim_in.Nchip = 1; +endfunction + +function test_curves + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 50; + sim_in.hf_sim = 0; + sim_in.Ntrials = 1000; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 5:15; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.Nchip = 4; + sim_dqpsk_hf_dsss = ber_test(sim_in, 'dqpsk'); + sim_in.hf_mag_only = 1; + sim_qpsk_hf_dsss = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;') + semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'b;QPSK HF;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'k;DQPSK HF;') + semilogy(sim_dqpsk_hf_dsss.Ebvec, sim_dqpsk_hf_dsss.BERvec,'g;DQPSK DSSS HF;') + semilogy(sim_qpsk_hf_dsss.Ebvec, sim_qpsk_hf_dsss.BERvec,'r;QPSK DSSS HF;') + hold off; + + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + +function test_single + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 10; + sim_in.hf_sim = 1; + sim_in.Nchip = 4; + sim_in.Ntrials = 500; + + sim_qpsk_hf = ber_test(sim_in, 'dqpsk'); +endfunction + +function test_1600_v_450 + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + sim_in.Ntrials = 500; + sim_in.hf_sim = 1; + + sim_in.framesize = 32; + sim_in.Nc = 16; + sim_in.Esvec = 7; + sim_in.Nchip = 1; + + sim_dqpsk_hf_1600 = ber_test(sim_in, 'dqpsk'); + + sim_in.framesize = 8; + sim_in.Nc = 4; + sim_in.Esvec = sim_in.Esvec + 10*log10(1600/450); + sim_in.Nchip = 4; + + sim_dqpsk_hf_450 = ber_test(sim_in, 'dqpsk'); + + fep=fopen("errors_1600.bin","wb"); fwrite(fep, sim_dqpsk_hf_1600.errors_log, "short"); fclose(fep); + fep=fopen("errors_450.bin","wb"); fwrite(fep, sim_dqpsk_hf_450.errors_log, "short"); fclose(fep); + +endfunction + + +% Start simulations --------------------------------------- + +more off; + +%test_1600_v_450(); +test_curves(); diff --git a/codec2/branches/0.7/octave/test_dsss_pilot.m b/codec2/branches/0.7/octave/test_dsss_pilot.m new file mode 100644 index 00000000..1d3ec169 --- /dev/null +++ b/codec2/branches/0.7/octave/test_dsss_pilot.m @@ -0,0 +1,437 @@ +% test_dsss_pilot.m +% David Rowe Oct 2014 +% + +% Simulation to test FDM QPSK with pilot based coherent detection +% combined with DSSS. + +% reqd to make sure we can repeat tests exactly + +rand('state',1); +randn('state',1); + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + Nchip = sim_in.Nchip; + Np = sim_in.Np; + Ns = sim_in.Ns; + + bps = 2; + Nc = Nsymb = framesize/bps; + + prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc*Nchip); + prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc*Nchip); + + tx_bits_mem = zeros(Np*Ns+1, framesize); + tx_symb_mem = zeros(Np*Ns+1, Nc*Nchip); + s_ch_mem = zeros(Np*Ns+1, Nc*Nchip); + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread(1:Ntrials))+var(spread_2ms(1:Ntrials))); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + s_ch_tx_log = []; + rx_symb_log = []; + noise_log = []; + errors_log = []; + Nerrs_log = []; + + % init HF channel + + hf_n = 1; + phi_ = zeros(Ntrials+Np*Ns, Nc*Nchip); + + phase_offset = 0; + w_offset = 0; + + % simulation starts here----------------------------------- + + for nn = 1:Ntrials+Np*Ns + + tx_bits = round( rand( 1, framesize) ); + tx_bits_mem(1:Np*Ns,:) = tx_bits_mem(2:Np*Ns+1,:); + for b=1:framesize + tx_bits_mem(Np*Ns+1,b) = tx_bits(b); + end + + % modulate -------------------------------------------- + + tx_symb = zeros(1,Nc*Nchip); + + for i=1:Nc + tx_symb(i) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + end + + % Optionally copy to other carriers (spreading) + + for i=Nc+1:Nc:Nc*Nchip + tx_symb(i:i+Nc-1) = tx_symb(1:Nc); + end + + % Optionally DQPSK encode + + if strcmp(modulation,'dqpsk') + for c=1:Nc*Nchip + tx_symb(c) *= prev_sym_tx(c); + prev_sym_tx(c) = tx_symb(c); + end + end + + tx_symb_mem(1:Np*Ns,:) = tx_symb_mem(2:Np*Ns+1,:); + for c=1:Nc*Nchip + tx_symb_mem(Np*Ns+1,c) = tx_symb(c); + end + + s_ch = tx_symb/sqrt(Nchip); + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + hf_model(hf_n, :) = zeros(1,Nc*Nchip); + + for i=1:Nchip + time_shift = floor(i*Rs/4); + for k=1:Nc + ahf_model = hf_gain*(spread(hf_n+time_shift) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n+time_shift)); + if hf_mag_only + s_ch((i-1)*Nc+k) *= abs(ahf_model); + else + s_ch((i-1)*Nc+k) *= ahf_model; + end + hf_model(hf_n, (i-1)*Nc+k) = ahf_model; + end + end + hf_n++; + end + + s_ch_tx_log = [s_ch_tx_log s_ch]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb*Nchip) + j*randn(1,Nsymb*Nchip)); + noise_log = [noise_log noise]; + + s_ch = s_ch.*exp(j*phase_offset) + noise; + phase_offset += w_offset; + + s_ch_mem(1:Np*Ns,:) = s_ch_mem(2:Np*Ns+1,:); + for c=1:Nc*Nchip + s_ch_mem(Np*Ns+1,c) = s_ch(c); + end + + % pilot based phase estimation and correction + + if Np + for c=1:Nc*Nchip + pilots = tx_symb_mem(:,c); + pilots(floor(Np*Ns/2)+1) = 0; + phi_(nn,c) = angle(pilots(1:Ns:Np*Ns+1)'*s_ch_mem(1:Ns:Np*Ns+1,c)); + end + end + + % demodulate stage 1 + + for c=1:Nc*Nchip + rx_symb(c) = s_ch_mem(floor(Np*Ns/2)+1,c) *exp(-j*phi_(nn,c)); + if strcmp(modulation,'dqpsk') + tmp = rx_symb(c); + rx_symb(c) *= conj(prev_sym_rx(c)/abs(prev_sym_rx(c))); + prev_sym_rx(c) = tmp; + end + end + + % de-spread + + for i=Nc+1:Nc:Nchip*Nc + rx_symb(1:Nc) = rx_symb(1:Nc) + rx_symb(i:i+Nc-1); + end + + % demodulate stage 2 (start when we have Np*Ns symbols in memories) + + if nn > Np*Ns + rx_bits = zeros(1, framesize); + for c=1:Nc + rx_bits((2*(c-1)+1):(2*c)) = qpsk_demod(rx_symb(c)); + tx_bits((2*(c-1)+1):(2*c)) = tx_bits_mem(floor(Np*Ns/2)+1,(2*(c-1)+1):(2*c)); + end + rx_symb_log = [rx_symb_log rx_symb(1:Nc)]; + + % Measure BER + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + end + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + if verbose + av_tx_pwr = (s_ch_tx_log * s_ch_tx_log')/length(s_ch_tx_log); + + printf("EsNo (dB): %3.1f Terrs: %d BER %4.2f QPSK BER theory %4.2f av_tx_pwr: %3.2f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + if hf_sim + figure(3); + clf; + + y = 1:(hf_n-1); + x = 1:Nc*Nchip; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + mesh(x,y,EsNodBSurface); + grid + axis([1 (Nc+1)*Nchip 1 Rs*5 -5 15]) + title('HF Channel Es/No'); + + if verbose + [m n] = size(hf_model); + av_hf_pwr = sum(sum(abs(hf_model(:,:)).^2))/(m*n); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, m*n); + end + + figure(5); + clf + subplot(211) + [m n] = size(hf_model); + plot(angle(hf_model(1:m,1)),'g;HF channel phase;') + hold on; + lphi_ = length(phi_); + plot(phi_(1+floor(Ns*Np/2):lphi_),'r+;Estimated HF channel phase;') + ylabel('Phase (rads)'); + subplot(212) + plot(abs(hf_model(1:m,1))) + ylabel('Amplitude'); + xlabel('Time (symbols)'); + end + + figure(4) + clf + stem(Nerrs_log) + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.framesize = 2; + sim_in.Rs = 50; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; + + sim_in.Nchip = 1; +endfunction + +function test_curves + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 10; + sim_in.hf_sim = 1; + sim_in.Ntrials = 1000; + sim_in.Rs = 200; + sim_in.Np = 4; + sim_in.Ns = 8; + sim_in.Nchip = 1; + + sim_qpsk = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 10:20; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + sim_in.Np = 0; + sim_in.Nchip = 1; + + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + sim_qpsk_hf_ideal = ber_test(sim_in, 'qpsk'); + sim_in.hf_mag_only = 0; + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.Np = 6; + sim_qpsk_hf_pilot = ber_test(sim_in, 'qpsk'); + sim_in.Nchip = 2; + sim_qpsk_hf_pilot_dsss = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;') + semilogy(sim_qpsk_hf_ideal.Ebvec, sim_qpsk_hf_ideal.BERvec,'b;QPSK HF ideal;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'k;DQPSK HF;') + semilogy(sim_qpsk_hf_pilot.Ebvec, sim_qpsk_hf_pilot.BERvec,'r;QPSK Np=6 HF;') + semilogy(sim_qpsk_hf_pilot_dsss.Ebvec, sim_qpsk_hf_pilot_dsss.BERvec,'g;QPSK Np=6 Nchip=2 HF;') + hold off; + + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + +function test_single + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Ntrials = 1000; + sim_in.Esvec = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; + sim_in.Nchip = 2; + sim_in.Np = 6; + sim_in.Ns = 8; + sim_in.Rs = 200; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); +endfunction + + +% Start simulations --------------------------------------- + +more off; +test_curves(); +%test_single(); diff --git a/codec2/branches/0.7/octave/test_fec.m b/codec2/branches/0.7/octave/test_fec.m new file mode 100644 index 00000000..710ec490 --- /dev/null +++ b/codec2/branches/0.7/octave/test_fec.m @@ -0,0 +1,406 @@ +% test_fec.m +% David Rowe Oct 2014 +% + +% Simulation to test FDM QPSK combined with FEC. A low rate Codec +% (e.g. 450 bit/s) is transmitted on Nc=4 FDM carriers. FEC parity +% bits are repeated on a seperate block of 4 carriers that is delayed +% in time by Rs symbols (1 second). A (n,k) Read Solomon code that can +% correct (n-k)/2 errors is simulated. + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + n = sim_in.n; + k = sim_in.k; % k message bits + Nc = sim_in.Nc; % number of carriers + + bps = 2; + Nsymb = n/bps; % total number of symbols + Nb = Nsymb/Nc; % length of block of symbols + assert(Nb == floor(Nb), "Nb must be an integer"); + + Nck = (k/n)*Nc; % Number of carriers for data symbols + Ncp = ((n-k)/n)*Nc; % Number of carriers for parity symbols + assert(Nck == floor(Nck), "Number of carriers for data symbols must be an integer"); + assert(Ncp == floor(Ncp), "Number of carriers for parity symbols must be an integer"); + + printf("(n,k)=(%d,%d) Nsymb: %d Nc: %d Nb: %d Nck: %d Ncp: %d\n",n,k,Nsymb,Nc,Nb,Nck,Ncp); + + prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc); + prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc); + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + errors_log = []; + Nerrs_log = []; + + % init HF channel + + hf_n = 1; + + % simulation starts here----------------------------------- + + for nn = 1: Ntrials + + tx_bits = round(rand(1,n)); + + % modulate -------------------------------------------- + + tx_symb=zeros(Nc,Nb); + + for b=1:Nb + for c=1:Nc + i = (b-1)*Nc + c; + tx_symb(c,b) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + if strcmp(modulation,'dqpsk') + tx_symb(c,b) *= prev_sym_tx(c); + prev_sym_tx(c) = tx_symb(c,b); + end + end + end + s_ch = tx_symb; + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + for b=1:Nb + + % apply HF model to data symbol carriers + + for c=1:Nck + ahf_model = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n)); + if hf_mag_only + s_ch(c,b) *= abs(ahf_model); + else + s_ch(c,b) *= ahf_model; + end + hf_model(hf_n, c) = ahf_model; + end + + % apply HF model (time shifted into the future) to parity symbol carriers + + for c=1:Ncp + ahf_model = hf_gain*(spread(hf_n+Rs) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n+Rs)); + if hf_mag_only + s_ch(Nck+c,b) *= abs(ahf_model); + else + s_ch(Nck+c,b) *= ahf_model; + end + hf_model(hf_n, Nck+c) = ahf_model; + end + + hf_n++; + end + end + + for b=1:Nb + for c=1:Nc + tx_symb_log = [tx_symb_log s_ch(c,b)]; + end + end + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(Nc,Nb) + j*randn(Nc,Nb)); + + s_ch = s_ch + noise; + + % de-modulate + + rx_bits = zeros(1, n); + for b=1:Nb + for c=1:Nc + rx_symb(c,b) = s_ch(c,b); + if strcmp(modulation,'dqpsk') + tmp = rx_symb(c,b); + rx_symb(c,b) *= conj(prev_sym_rx(c)/abs(prev_sym_rx(c))); + prev_sym_rx(c) = tmp; + end + i = (b-1)*Nc + c; + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb(c,b)); + rx_symb_log = [rx_symb_log rx_symb(c,b)]; + end + end + + % Measure BER + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + av_tx_pwr = (tx_symb_log * tx_symb_log')/length(tx_symb_log) + + printf("EsNo (dB): %3.1f Terrs: %d BER %4.3f QPSK BER theory %4.3f av_tx_pwr: %3.2f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + if hf_sim + figure(3); + clf; + + y = 1:(hf_n-1); + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + mesh(x,y,EsNodBSurface); + grid + axis([1 Nc 1 Rs*5 -5 15]) + title('HF Channel Es/No'); + + if verbose + av_hf_pwr = sum(abs(hf_model(y)).^2)/(hf_n-1); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, hf_n-1); + end + end + + figure(4) + clf + stem(Nerrs_log) + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.Rs = 50; + sim_in.Nc = 8; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; +endfunction + +function test_curves + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 50; + sim_in.hf_sim = 0; + sim_in.Ntrials = 1000; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 5:15; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + sim_in.hf_mag_only = 0; + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.Nchip = 4; + sim_dqpsk_hf_dsss = ber_test(sim_in, 'dqpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;') + semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'b;QPSK HF;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'k;DQPSK HF;') + semilogy(sim_dqpsk_hf_dsss.Ebvec, sim_dqpsk_hf_dsss.BERvec,'g;DQPSK DSSS HF;') + hold off; + + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + +function test_1600_v_450 + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + sim_in.Ntrials = 500; + sim_in.hf_sim = 1; + + sim_in.framesize = 32; + sim_in.Nc = 16; + sim_in.Esvec = 7; + sim_in.Nchip = 1; + + sim_dqpsk_hf_1600 = ber_test(sim_in, 'dqpsk'); + + sim_in.framesize = 8; + sim_in.Nc = 4; + sim_in.Esvec = sim_in.Esvec + 10*log10(1600/450); + sim_in.Nchip = 4; + + sim_dqpsk_hf_450 = ber_test(sim_in, 'dqpsk'); + + fep=fopen("errors_1600.bin","wb"); fwrite(fep, sim_dqpsk_hf_1600.errors_log, "short"); fclose(fep); + fep=fopen("errors_450.bin","wb"); fwrite(fep, sim_dqpsk_hf_450.errors_log, "short"); fclose(fep); + +endfunction + +function test_single + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.n = 48*8; + sim_in.k = 24*8; + snr = 1; + sim_in.Esvec = snr + 10*log10(3000/400); + sim_in.hf_sim = 1; + sim_in.Ntrials = 100; + + sim_qpsk_hf = ber_test(sim_in, 'dqpsk'); +endfunction + + +% Start simulations --------------------------------------- + +more off; + +%test_1600_v_450(); +%test_curves(); +test_single(); diff --git a/codec2/branches/0.7/octave/test_foff.m b/codec2/branches/0.7/octave/test_foff.m new file mode 100644 index 00000000..34afed3d --- /dev/null +++ b/codec2/branches/0.7/octave/test_foff.m @@ -0,0 +1,402 @@ +% test_foff.m +% David Rowe April 2015 +% +% Octave script for testing the cohpsk freq offset estimator + +graphics_toolkit ("gnuplot"); +more off; + +cohpsk; +fdmdv; +autotest; + +rand('state',1); +randn('state',1); + + +% Core function for testing frequency offset estimator. Performs one test + +function sim_out = freq_off_est_test(sim_in) + global Nfilter; + global M; + + Rs = 100; + Nc = 4; + Nd = 2; + framesize = 32; + Fs = 8000; + Fcentre = 1500; + + Nsw = 3; % numbers of sync window frames we process over. Set based + % on Nsym to flush filter memory by final frame in windw + + afdmdv.Nsym = 5; + afdmdv.Nt = 5; + + afdmdv.Fs = 8000; + afdmdv.Nc = Nd*Nc-1; + afdmdv.Rs = Rs; + M = afdmdv.M = afdmdv.Fs/afdmdv.Rs; + afdmdv.Nfilter = afdmdv.Nsym*M; + afdmdv.tx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter); + excess_bw = 0.5; + afdmdv.gt_alpha5_root = gen_rn_coeffs(excess_bw, 1/Fs, Rs, afdmdv.Nsym, afdmdv.M); + afdmdv.Fsep = afdmdv.Rs*(1+excess_bw); + afdmdv.phase_tx = ones(afdmdv.Nc+1,1); + freq_hz = afdmdv.Fsep*( -Nc*Nd/2 - 0.5 + (1:Nc*Nd).^1.1 ); + afdmdv.freq_pol = 2*pi*freq_hz/Fs; + afdmdv.freq = exp(j*afdmdv.freq_pol); + afdmdv.Fcentre = 1500; + + afdmdv.fbb_rect = exp(j*2*pi*Fcentre/Fs); + afdmdv.fbb_phase_tx = 1; + afdmdv.fbb_phase_rx = 1; + %afdmdv.phase_rx = ones(afdmdv.Nc+1,1); + afdmdv.phase_rx = 1 - 2*(mod(1:Nc*Nd,2)); + nin = M; + + P = afdmdv.P = 4; + afdmdv.Nfilter = afdmdv.Nsym*afdmdv.M; + afdmdv.rx_filter_mem_timing = zeros(afdmdv.Nc+1, afdmdv.Nt*afdmdv.P); + afdmdv.Nfiltertiming = afdmdv.M + afdmdv.Nfilter + afdmdv.M; + afdmdv.rx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter); + + acohpsk = standard_init(); + acohpsk.framesize = framesize; + acohpsk.ldpc_code = 0; + acohpsk.ldpc_code_rate = 1; + acohpsk.Nc = Nc; + acohpsk.Rs = Rs; + acohpsk.Ns = 4; + acohpsk.Nd = Nd; + acohpsk.modulation = 'qpsk'; + acohpsk.do_write_pilot_file = 0; + acohpsk = symbol_rate_init(acohpsk); + acohpsk.Ncm = 10*acohpsk.Nsymbrowpilot*M; + acohpsk.coarse_mem = zeros(1,acohpsk.Ncm); + acohpsk.Ndft = 2^(ceil(log2(acohpsk.Ncm))); + + ch_fdm_frame_buf = zeros(1, Nsw*acohpsk.Nsymbrowpilot*M); + + frames = sim_in.frames; + EsNodB = sim_in.EsNodB; + foff = sim_in.foff; + dfoff = sim_in.dfoff; + fading_en = sim_in.fading_en; + + EsNo = 10^(EsNodB/10); + hf_delay_ms = 2; + phase_ch = 1; + + rand('state',1); + tx_bits_coh = round(rand(1,framesize*10)); + ptx_bits_coh = 1; + [spread spread_2ms hf_gain] = init_hf_model(Fs, frames*acohpsk.Nsymbrowpilot*afdmdv.M); + + hf_n = 1; + nhfdelay = floor(hf_delay_ms*Fs/1000); + ch_fdm_delay = zeros(1, acohpsk.Nsymbrowpilot*M + nhfdelay); + + sync = 0; next_sync = 1; + sync_start = 1; + freq_offset_log = []; + sync_time_log = []; + ch_fdm_frame_log = []; + ch_symb_log = []; + tx_fdm_frame_log = []; + ratio_log = []; + + for f=1:frames + + acohpsk.frame = f; + + % + % Mod -------------------------------------------------------------------- + % + + tx_bits = tx_bits_coh(ptx_bits_coh:ptx_bits_coh+framesize-1); + ptx_bits_coh += framesize; + if ptx_bits_coh > length(tx_bits_coh) + ptx_bits_coh = 1; + end + + [tx_symb tx_bits] = bits_to_qpsk_symbols(acohpsk, tx_bits, [], []); + + tx_fdm_frame = []; + for r=1:acohpsk.Nsymbrowpilot + tx_onesymb = tx_symb(r,:); + [tx_baseband afdmdv] = tx_filter(afdmdv, tx_onesymb); + [tx_fdm afdmdv] = fdm_upconvert(afdmdv, tx_baseband); + tx_fdm_frame = [tx_fdm_frame tx_fdm]; + end + tx_fdm_frame_log = [tx_fdm_frame_log tx_fdm_frame]; + + % + % Channel -------------------------------------------------------------------- + % + + ch_fdm_frame = zeros(1,acohpsk.Nsymbrowpilot*M); + for i=1:acohpsk.Nsymbrowpilot*M + foff_rect = exp(j*2*pi*foff/Fs); + foff += dfoff; + phase_ch *= foff_rect; + ch_fdm_frame(i) = tx_fdm_frame(i) * phase_ch; + end + phase_ch /= abs(phase_ch); + + if fading_en + ch_fdm_delay(1:nhfdelay) = ch_fdm_delay(acohpsk.Nsymbrowpilot*M+1:nhfdelay+acohpsk.Nsymbrowpilot*M); + ch_fdm_delay(nhfdelay+1:nhfdelay+acohpsk.Nsymbrowpilot*M) = ch_fdm_frame; + + for i=1:acohpsk.Nsymbrowpilot*M + ahf_model = hf_gain*(spread(hf_n)*ch_fdm_frame(i) + spread_2ms(hf_n)*ch_fdm_delay(i)); + ch_fdm_frame(i) = ahf_model; + hf_n++; + end + end + + % each carrier has power = 2, total power 2Nc, total symbol rate NcRs, noise BW B=Fs + % Es/No = (C/Rs)/(N/B), N = var = 2NcFs/NcRs(Es/No) = 2Fs/Rs(Es/No) + + variance = 2*Fs/(acohpsk.Rs*EsNo); + uvnoise = sqrt(0.5)*(randn(1,acohpsk.Nsymbrowpilot*M) + j*randn(1,acohpsk.Nsymbrowpilot*M)); + noise = sqrt(variance)*uvnoise; + + ch_fdm_frame += noise; + ch_fdm_frame_log = [ch_fdm_frame_log ch_fdm_frame]; + + % + % Try to achieve sync -------------------------------------------------------------------- + % + + % store Nsw frames so we can rewind if we get a good candidate + + ch_fdm_frame_buf(1:(Nsw-1)*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame_buf(acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M); + ch_fdm_frame_buf((Nsw-1)*acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame; + + next_sync = sync; + sync = 0; + + if sync == 0 + + % we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz + + max_ratio = 0; + for acohpsk.f_est = Fcentre-40:40:Fcentre+40 + %for acohpsk.f_est = Fcentre + + printf(" [%d] acohpsk.f_est: %f +/- 20\n", f, acohpsk.f_est); + [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est ] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0); + + % coarse timing (frame sync) and initial fine freq est --------------------------------------------- + + for i=1:Nsw-1 + acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot); + end + [anext_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync); + + if anext_sync == 1 + printf(" [%d] acohpsk.ratio: %f\n", f, acohpsk.ratio); + if acohpsk.ratio > max_ratio + max_ratio = acohpsk.ratio; + f_est = acohpsk.f_est - acohpsk.f_fine_est; + next_sync = anext_sync; + end + end + end + end + + % we've found a sync candidate + + if (next_sync == 1) + + % rewind and re-process last few frames with f_est + + acohpsk.f_est = f_est; + printf(" [%d] trying sync and f_est: %f\n", f, acohpsk.f_est); + [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0); + ch_symb_log = ch_symb; + for i=1:Nsw-1 + acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot); + end + [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync); + if abs(acohpsk.f_fine_est) > 2 + printf(" [%d] Hmm %f is a bit big so back to coarse est ...\n", f, acohpsk.f_fine_est); + next_sync = 0; + end + + % candidate checks out so log stats + + if (next_sync == 1) + printf(" [%d] in sync!\n", f); + freq_offset_log = [freq_offset_log Fcentre+foff-acohpsk.f_est]; + sync_time_log = [sync_time_log f-sync_start]; + ratio_log = [ratio_log max_ratio]; + next_sync = 0; sync_start = f; + end + end + + %printf("f: %d sync: %d next_sync: %d\n", f, sync, next_sync); + [sync acohpsk] = sync_state_machine(acohpsk, sync, next_sync); + + end + + % ftx=fopen("coarse_tx.raw","wb"); fwrite(ftx, 1000*ch_fdm_frame_log, "short"); fclose(ftx); + + sim_out.freq_offset_log = freq_offset_log; + sim_out.sync_time_log = sync_time_log; + sim_out.ch_fdm_frame_log = ch_fdm_frame_log; + sim_out.ch_symb_log = ch_symb_log; + sim_out.tx_fdm_frame_log = tx_fdm_frame_log; + sim_out.ratio_log = ratio_log; +endfunction + + +function freq_off_est_test_single + sim_in.frames = 5; + sim_in.EsNodB = 120; + sim_in.foff = 0; + sim_in.dfoff = 0; + sim_in.fading_en = 0; + + sim_out = freq_off_est_test(sim_in); + + figure(1) + subplot(211) + plot(sim_out.freq_offset_log) + ylabel('f est error') + xlabel('time') + + subplot(212) + if length(sim_out.freq_offset_log) > 0 + hist(sim_out.freq_offset_log) + xlabel('f est error') + ylabel('histogram'); + end + + figure(2) + subplot(211) + plot(sim_out.sync_time_log) + ylabel('time to sync (frames)') + subplot(212) + if length(sim_out.sync_time_log) > 0 + hist(sim_out.sync_time_log) + xlabel('time to sync (frames)') + ylabel('histogram') + end + + figure(3) + subplot(211) + plot(real(sim_out.tx_fdm_frame_log(1:2*960))) + grid; + subplot(212) + plot(real(sim_out.ch_symb_log),'+') + grid; + + figure(4) + clf; + plot(sim_out.ch_symb_log,'+') + + figure(5) + clf; + plot(sim_out.ratio_log) + xlabel('time') + ylabel('ratio for sync') +endfunction + + +function [freq_off_log EsNodBSet] = freq_off_est_test_curves + EsNodBSet = [20 12 8]; + + sim_in.frames = 100; + sim_in.foff = -40; + sim_in.dfoff = 0; + sim_in.fading_en = 1; + freq_off_log = 1E6*ones(sim_in.frames, length(EsNodBSet) ); + sync_time_log = 1E6*ones(sim_in.frames, length(EsNodBSet) ); + + for i=1:length(EsNodBSet) + sim_in.EsNodB = EsNodBSet(i); + printf("%f\n", sim_in.EsNodB); + + sim_out = freq_off_est_test(sim_in); + freq_off_log(1:length(sim_out.freq_offset_log),i) = sim_out.freq_offset_log; + sync_time_log(1:length(sim_out.sync_time_log),i) = sim_out.sync_time_log; + end + + figure(1) + clf + hold on; + for i=1:length(EsNodBSet) + data = freq_off_log(find(freq_off_log(:,i) < 1E6),i); + s = std(data); + m = mean(data); + stdbar = [m-s; m+s]; + plot(EsNodBSet(i), data, '+') + plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-') + end + hold off + + axis([6 22 -25 25]) + if sim_in.fading_en + title_str = sprintf('foff = %d Hz Fading', sim_in.foff); + else + title_str = sprintf('foff = %d Hz AWGN', sim_in.foff); + end + title(title_str); + xlabel('Es/No (dB)') + ylabel('freq offset error (Hz)'); + + figure(2) + clf + hold on; + for i=1:length(EsNodBSet) + leg = sprintf("%d;%d dB;", i, EsNodBSet(i)); + plot(freq_off_log(find(freq_off_log(:,i) < 1E6),i),leg) + end + hold off; + title(title_str); + xlabel('test'); + ylabel('freq offset error (Hz)'); + legend('boxoff'); + + figure(3) + clf + hold on; + for i=1:length(EsNodBSet) + data = sync_time_log(find(sync_time_log(:,i) < 1E6),i); + if length(data) + s = std(data); + m = mean(data); + stdbar = [m-s; m+s]; + plot(EsNodBSet(i), data, '+') + plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-') + end + end + hold off; + axis([6 22 0 10]) + ylabel('sync time (frames)') + xlabel('Es/No (dB)'); + title(title_str); + + figure(4) + clf + hold on; + for i=1:length(EsNodBSet) + leg = sprintf("%d;%d dB;", i, EsNodBSet(i)); + plot(sync_time_log(find(sync_time_log(:,i) < 1E6),i),leg) + end + hold off; + title(title_str); + xlabel('test'); + ylabel('sync time (frames)'); + legend('boxoff'); + +endfunction + + +% select on of these to run: + +freq_off_est_test_single; +%freq_off_est_test_curves; + diff --git a/codec2/branches/0.7/octave/test_ftrack.m b/codec2/branches/0.7/octave/test_ftrack.m new file mode 100644 index 00000000..5082c443 --- /dev/null +++ b/codec2/branches/0.7/octave/test_ftrack.m @@ -0,0 +1,197 @@ +% test_ftrack.m +% +% David Rowe May 2015 +% +% Octave script that to test and develop symbol rate frequency offset +% tracking +% +% [X] add Es/No noise and measure BER +% [X] QPSK mod of random symbols +% [X] tracking 1 Hz/s freq drift shiel staying in lock +% [X] simulate R/N filter delay through filter + +rand('state',1); +randn('state',1); +graphics_toolkit ("gnuplot"); + +Fs = 8000; % sample rate +Rs = 50; % QPSK modem symbol rate +Nbits = 5000; % number of bits to simulute over +Nsymb = Nbits/2; +foff = 1; % initial freq offset +dfoff = -1/Fs; % rate of change of frequency offset in Hz/sample +M = Fs/Rs; % oversampling rate + +EsNodB = 8; % noise level +EsNo = 10^(EsNodB/10); +variance = 1/EsNo; + +Nsym = 5; % simulated delay of root nyquist filter in symbols + +% control system constants, these can be tweaked + +beta = 0.005; +g = 0.2; + +% init state variables + +phase_ch = 1; +prev_rx_symb = 1; +ftrack = 0; +filt = 0; + +% QPSK symbols ------> x -------> x ----------G(z) ------------\ +% | | | +% exp(j*w_off*n) | | +% | | +% exp(-j*w_track*n) | +% \____________________________/ +% +% for small phase/freq errors, where phase/freq detector is linear: +% +% -1 beta 1 1 +% G(z) = 1 - z g --------------- -------- ------- +% -1 -1 -1 +% 1 - (1-beta)z 1 - z 1 - z +% +% (1) (2) (3) (4) +% +% (1) - differentiator that gives us an error based on frequency difference +% (2) - first order IIR loop filter +% (3) - integrator I added so loop could track ramp inputs (i.e. freq drift) +% (4) - frequency to phase integrator implicit in VCO +% +% Note (1) and (3) cancel out, H(z) = 1, so we get a 2nd order loop. We need to keep (1) +% in the time domain implementation to make the modulation stripper work, it likes angles +% near 0. +% +% Transfer function, derived with pencil and paper: +% +% G(z) g*beta +% ------------ = ---------- * ------------------------------------ +% 1 + G(z)H(z) 1 + g*beta 2 - beta -1 1 - beta -2 +% 1 - ---------- z + ----------- z +% 1 + g*beta 1 + g*beta + +% Second order IIR filter coeffs + +a1 = (2-beta)/(1+g*beta); +a2 = (1-beta)/(1+g*beta); + +% Which can be used to work out the polar coordinates of the pole + +gamma = sqrt(a2); % radius (distance from origin) +w = acos(a1/(2*gamma)); % angular frequency + +printf("2nd order loop w: %f gamma: %f\n", w, gamma); + + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + + +% modulator + +tx_bits = rand(1, Nbits) > 0.5; +tx_symb = zeros(1, Nsymb); +for i=1:Nsymb + tx_symb(i) = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); +end + +% run rest of simulation symbol by symbol + +rx_symb = zeros(1, Nsymb); +rx_filt = zeros(1,Nsym); + +diff_log = []; +foff_log = []; +ftrack_log = []; +mod_strip_log = []; + +for i=1:Nsymb + + % channel + + foff_rect = exp(j*2*pi*(foff-ftrack)*M/Fs); + foff += M*dfoff; + phase_ch *= foff_rect; + rx_symb(i) = tx_symb(i) * phase_ch; + noise = sqrt(variance*0.5)*(randn(1,1) + j*randn(1, 1)); + rx_symb(i) += noise; + + % simulate delay of root nyquist filter + + rx_filt(1:Nsym-1) = rx_filt(2:Nsym); + rx_filt(Nsym) = rx_symb(i); + + % freq tracking loop + + diff = rx_filt(1) .* conj(prev_rx_symb); + prev_rx_symb = rx_filt(1); + + % 4th power strips QPSK modulation, by multiplying phase by 4 + % Using the abs value of the real coord was found to help + % non-linear issues when noise power was large + + mod_strip = diff.^4; + mod_strip = abs(real(mod_strip)) + j*imag(mod_strip); + + % loop filter made up of 1st order IIR plus integrator plus gain + % term. Integrator was found to be reqd to track ramp inputs + % (i.e. freq drift) + + filt = ((1-beta)*filt + beta*angle(mod_strip)); + ftrack += g*filt; + + diff_log = [diff_log diff]; + foff_log = [foff_log foff]; + ftrack_log = [ftrack_log ftrack]; + mod_strip_log = [mod_strip_log mod_strip]; +end + +% plot results + +figure(1) +clf +plot(angle(mod_strip_log)) +title('mod stripping phase'); + +figure(2); +clf +plot(mod_strip_log,'+') +axis([-2 2 -2 2]) +title('mod stripping scatter'); + +figure(3) +clf +subplot(211) +plot(real(mod_strip_log)) +title('mod stripping real and imag'); +subplot(212) +plot(imag(mod_strip_log)) + +figure(4) +clf +subplot(211) +plot(foff_log,';foff;') +hold on +plot(ftrack_log,'g+;ftrack;') +hold off; +legend("boxoff"); +ylabel('Freq Offset Hz'); + +subplot(212) +plot(foff_log-ftrack_log,';foff-ftrack;' ) +ylabel('Freq Offset Tracking Error Hz'); +xlabel('symbols') +legend("boxoff"); + +figure(5) +freqz(g*beta/(1+g*beta), [1 -2*gamma*cos(w) gamma*gamma]) diff --git a/codec2/branches/0.7/octave/test_ldpc_fsk_lib.m b/codec2/branches/0.7/octave/test_ldpc_fsk_lib.m new file mode 100644 index 00000000..4a6148a4 --- /dev/null +++ b/codec2/branches/0.7/octave/test_ldpc_fsk_lib.m @@ -0,0 +1,851 @@ +% test_ldpc_fsk_lib +% David Rowe 16 April 2016 +% +% A series of tests for ldpc_fsk_lib, and C versions ldpc_enc and ldpc_dec. +% Gradually builds up complete C command line for SSTV balloon system, +% using Octave versions of LDPC and FSK modem as reference points. + +1; + +% encodes and decodes one frame, also writes codeword.bin for testing +% decode_from_file() below, and can optionally generate include file for +% C version of decoder. + +function [data code_param] = simple_ut(c_include_file) + load('H2064_516_sparse.mat'); + HRA = full(HRA); + max_iterations = 100; + decoder_type = 0; + EsNodB = 3; + mod_order = 2; + + code_param = ldpc_init(HRA, mod_order); + data = round( rand( 1, code_param.data_bits_per_frame ) ); + codeword = ldpc_encode(code_param, data); + f = fopen("codeword.bin","wt"); fwrite(f, codeword, "uint8"); fclose(f); + s = 1 - 2 * codeword; + code_param.symbols_per_frame = length( s ); + + EsNo = 10^(EsNodB/10); + variance = 1/(2*EsNo); + noise = sqrt(variance)* randn(1,code_param.symbols_per_frame); + rx = s + noise; + + if nargin == 1 + code_param.c_include_file = c_include_file; + end + [detected_data Niters] = ldpc_decode(rx, code_param, max_iterations, decoder_type); + + error_positions = xor(detected_data(1:code_param.data_bits_per_frame), data); + Nerrs = sum(error_positions); + + printf("Nerrs = %d\n", Nerrs); +end + + +% This version decodes from a file of bits + +function detected_data = decode_from_file(filename) + max_iterations = 100; + decoder_type = 0; + load('H2064_516_sparse.mat'); + HRA = full(HRA); + mod_order = 2; + + f = fopen(filename,"rb"); codeword = fread(f, "uint8")'; fclose(f); + r = 1 - 2 * codeword; + code_param = ldpc_init(HRA, mod_order); + [detected_data Niters] = ldpc_decode(r, code_param, max_iterations, decoder_type); +end + + +% plots a BER curve for the LDPC decoder. Takes a while to run, uses parallel cores + +function plot_curve + num_cores = 4; % set this to the number of cores you have + + load('H2064_516_sparse.mat'); + HRA = full(HRA); + [Nr Nc] = size(HRA); + sim_in.rate = (Nc-Nr)/Nc; + + sim_in.HRA = HRA; + sim_in.mod_order = 2; + sim_in.framesize = Nc; + sim_in.mod_order = 2; + sim_in.Lim_Ferrs = 100; + + % note we increase number of trials as BER goes down + + Esvec = [ 0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 ]; + Ntrials = [ 1E4 1E4 1E4 1E4 1E5 1E5 1E5 1E5 1E5 ]; + num_runs = length(Esvec) + + sim_in_vec(1:num_runs) = sim_in; + for i = 1:num_runs + sim_in_vec(i).Esvec = Esvec(i); + sim_in_vec(i).Ntrials = Ntrials(i); + end + + %sim_out = ldpc5(sim_in_vec(1)); + tstart = time(); + sim_out = pararrayfun(num_cores, @ldpc5, sim_in_vec); + tend = time(); + + total_bits = sum(Ntrials)*sim_in.framesize; + total_secs = tend - tstart; + printf("%d bits in %4.1f secs, or %5f bits/s\n", total_bits, total_secs, total_bits/total_secs); + + for i=1:num_runs + Ebvec(i) = sim_out(i).Ebvec; + BERvec(i) = sim_out(i).BERvec; + end + semilogy(Ebvec, BERvec, '+-') + xlabel('Eb/N0') + ylabel('BER') + title(['H2064 516 sparse.mat' ' ' date]) + +end + + +% Test C encoder + +function test_c_encoder + load('H2064_516_sparse.mat'); + HRA = full(HRA); + max_iterations = 100; + decoder_type = 0; + EsNodB = 3; + mod_order = 2; + frames = 100; + + EsNo = 10^(EsNodB/10); + variance = 1/(2*EsNo); + + code_param = ldpc_init(HRA, mod_order); + + data = round(rand(1,frames*code_param.data_bits_per_frame)); + f = fopen("data.bin","wt"); fwrite(f, data, "uint8"); fclose(f); + + % Outboard C encoder + + system("../src/ldpc_enc data.bin codewords.bin"); + + % Test with Octave decoder + + f = fopen("codewords.bin","rb"); codewords = fread(f, "uint8")'; fclose(f); + + Nerrs = 0; + for i=1:frames + st = (i-1)*code_param.symbols_per_frame+1; en = st+code_param.symbols_per_frame-1; + tx = 1 - 2 * codewords(st:en); + + noise = sqrt(variance)*randn(1,code_param.symbols_per_frame); + rx = tx + noise; + + [detected_data Niters] = ldpc_decode(rx, code_param, max_iterations, decoder_type); + + st = (i-1)*code_param.data_bits_per_frame+1; en = st+code_param.data_bits_per_frame-1; + error_positions = xor(detected_data(1:code_param.data_bits_per_frame), data(st:en)); + Nerrs += sum(error_positions); + end + + printf("Nerrs = %d\n", Nerrs); +end + + +function test_c_decoder + load('H2064_516_sparse.mat'); + HRA = full(HRA); + max_iterations = 100; + decoder_type = 0; + mod_order = 2; + frames = 10; + EsNodB = 2; + sdinput = 1; + + EsNo = 10^(EsNodB/10); + variance = 1/(2*EsNo); + + code_param = ldpc_init(HRA, mod_order); + data = round(rand(1,code_param.data_bits_per_frame*frames)); + + f = fopen("data.bin","wt"); fwrite(f, data, "uint8"); fclose(f); + system("../src/ldpc_enc data.bin codewords.bin"); + f = fopen("codewords.bin","rb"); codewords = fread(f, "uint8")'; fclose(f); + + s = 1 - 2 * codewords; + noise = sqrt(variance)*randn(1,code_param.symbols_per_frame*frames); + r = s + noise; + + % calc LLRs frame by frame + + for i=1:frames + st = (i-1)*code_param.symbols_per_frame+1; + en = st + code_param.symbols_per_frame-1; + llr(st:en) = sd_to_llr(r(st:en)); + end + + % Outboard C decoder + + if sdinput + f = fopen("sd.bin","wb"); fwrite(f, r, "double"); fclose(f); + system("../src/ldpc_dec sd.bin data_out.bin --sd"); + else + f = fopen("llr.bin","wb"); fwrite(f, llr, "double"); fclose(f); + system("../src/ldpc_dec llr.bin data_out.bin"); + end + + f = fopen("data_out.bin","rb"); data_out = fread(f, "uint8")'; fclose(f); + + Nerrs = Nerrs2 = zeros(1,frames); + for i=1:frames + + % Check C decoder + + data_st = (i-1)*code_param.data_bits_per_frame+1; + data_en = data_st+code_param.data_bits_per_frame-1; + st = (i-1)*code_param.symbols_per_frame+1; + en = st+code_param.data_bits_per_frame-1; + data_out_c = data_out(st:en); + error_positions = xor(data_out_c, data(data_st:data_en)); + Nerrs(i) = sum(error_positions); + + % Octave decoder + + st = (i-1)*code_param.symbols_per_frame+1; en = st+code_param.symbols_per_frame-1; + [detected_data Niters] = ldpc_decode(r(st:en), code_param, max_iterations, decoder_type); + st = (i-1)*code_param.data_bits_per_frame+1; en = st+code_param.data_bits_per_frame-1; + data_out_octave = detected_data(1:code_param.data_bits_per_frame); + error_positions = xor(data_out_octave, data(st:en)); + Nerrs2(i) = sum(error_positions); + %printf("%4d ", Niters); + end + printf("Errors per frame:\nC.....:"); + for i=1:frames + printf("%4d ", Nerrs(i)); + end + printf("\nOctave:"); + for i=1:frames + printf("%4d ", Nerrs2(i)); + end + printf("\n"); + +end + +% Saves a complex vector s to a file "filename" of IQ unsigned 8 bit +% chars, same as RTLSDR format. + +function save_rtlsdr(filename, s) + mx = max(abs(s)); + re = real(s); im = imag(s); + l = length(s); + iq = zeros(1,2*l); + %iq(1:2:2*l) = 127 + re*(127/mx); + %iq(2:2:2*l) = 127 + im*(127/mx); + iq(1:2:2*l) = 127 + 32*re; + iq(2:2:2*l) = 127 + 32*im; + figure(3); clf; plot(iq); title('simulated IQ signal from RTL SDR'); + fs = fopen(filename,"wb"); + fwrite(fs,iq,"uchar"); + fclose(fs); +endfunction + + +% Oversamples by a factor of 2 using Octaves resample() function then +% uses linear interpolation to achive fractional sample rate + +function rx_resample_fract = fractional_resample(rx, resample_rate); + assert(resample_rate < 2, "keep resample_rate between 0 and 2"); + rx_resample2 = resample(rx, 2, 1); + l = length(rx_resample2); + rx_resample_fract = zeros(1,l); + k = 1; + step = 2/resample_rate; + for i=1:step:l-1 + i_low = floor(i); + i_high = ceil(i); + f = i - i_low; + rx_resample_fract(k) = (1-f)*rx_resample2(i_low) + f*rx_resample2(i_high); + %printf("i: %f i_low: %d i_high: %d f: %f\n", i, i_low, i_high, f); + k++; + end + rx_resample_fract = rx_resample_fract(1:k-1); +endfunction + + +% Using simulated SSTV packet, generate complex fsk mod signals, 8-bit +% unsigned IQ for feeding into C demod chain. Can also be used to +% generate BER curves. Found bugs in UW size and our use of csdr +% re-sampler using this function, and by gradually and carefully +% building up the C command line. + +#{ +todo: [X] uncoded BER + [X] octave fsk demod + [X] use C demod + [X] compare uncoded BER to unsigned 8 bit IQ to regular 16-bit + [X] generate complex rx signal with noise + [X] used cmd line utils to drive demod + [X] test with resampler + [X] measure effect on PER with coding +#} + +function [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodB) + + frames = sim_in.frames; + demod_type = sim_in.demod_type; + + % init LDPC code + + load('H2064_516_sparse.mat'); + HRA = full(HRA); + max_iterations = 100; + decoder_type = 0; + mod_order = 2; + + code_param = ldpc_init(HRA, mod_order); + + % note fixed frame of bits used for BER testing + + tx_codeword = gen_sstv_frame; + + % init FSK modem + + fsk_horus_as_a_lib = 1; + fsk_horus; + states = fsk_horus_init_hbr(9600, 8, 1200, 2, length(tx_codeword)); + states.df(1:states.M) = 0; + states.dA(1:states.M) = 1; + states.tx_real = 0; % Octave fsk_mod generates complex valued output + % so we can simulate rtl_sdr complex ouput + + % Set up simulated tx tones to sit in the middle of cdsr passband + + filt_low_norm = 0.1; filt_high_norm = 0.4; + fc = states.Fs*(filt_low_norm + filt_high_norm)/2; + %fc = 1800; + f1 = fc - states.Rs/2; + f2 = fc + states.Rs/2; + states.ftx = [f1 f2]; + + % set up AWGN channel + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % start simulation ---------------------------------------- + + tx_bit_stream = []; + for i=1:frames + % uncomment for different data on each frame + %tx_codeword = gen_sstv_frame; + tx_bit_stream = [tx_bit_stream tx_codeword]; + end + + printf("%d bits at %d bit/s is a %3.1f second run\n", length(tx_bit_stream), 115200,length(tx_bit_stream)/115200); + + % modulate and channel model + + tx = fsk_horus_mod(states, tx_bit_stream); + noise_real = sqrt(variance)*randn(length(tx),1); + noise_complex = sqrt(variance/2)*(randn(length(tx),1) + j*randn(length(tx),1)); + + % demodulate ----------------------------------------------------- + + if demod_type == 1 + + % Octave demod + + if states.tx_real + rx = tx + noise_real; + else + rx = tx + noise_complex; + end + SNRdB = 10*log10(var(tx)/var(noise_complex)); + + % demodulate frame by frame using Octave demod + + st = 1; + run_frames = floor(length(rx)/states.N); + rx_bit_stream = []; + rx_sd_stream = []; + for f=1:run_frames + + % extract nin samples from rx sample stream + + nin = states.nin; + en = st + states.nin - 1; + + if en <= length(rx) % due to nin variations its possible to overrun buffer + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + states.f = [f1 f2]; % note that for Octave demod we cheat and use known tone frequencies + % allows us to determine if freq offset estimation in C demod is a problem + + [rx_bits states] = fsk_horus_demod(states, sf); + rx_bit_stream = [rx_bit_stream rx_bits]; + rx_sd_stream = [rx_sd_stream states.rx_bits_sd]; + end + end + end + + if demod_type == 2 + % baseline C demod + + if states.tx_real + rx = tx + noise_real; + else + rx = 2*real(tx) + noise_real; + end + SNRdB = 10*log10(var(tx)/var(noise_real)); + rx_scaled = 1000*real(rx); + f = fopen("fsk_demod.raw","wb"); fwrite(f, rx_scaled, "short"); fclose(f); + system("../build_linux/src/fsk_demod 2X 8 9600 1200 fsk_demod.raw fsk_demod.bin"); + f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f); + end + + if demod_type == 3 + % C demod driven by csdr command line kung fu + + assert(states.tx_real == 0, "need complex signal for this test"); + rx = tx + noise_complex; + SNRdB = 10*log10(var(tx)/var(noise_real)); + save_rtlsdr("fsk_demod.iq", rx); + system("cat fsk_demod.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin"); + f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f); + end + + if demod_type == 4 + % C demod with resampler ....... getting closer to Mark's real time cmd line + + assert(states.tx_real == 0, "need complex signal for this test"); + rx = tx + noise_complex; + SNRdB = 10*log10(var(tx)/var(noise_real)); + + printf("resampling ...\n"); + rx_resample_fract = fractional_resample(rx, 1.08331); + %rx_resample_fract = fractional_resample(rx_resample_fract, 1/1.08331); + save_rtlsdr("fsk_demod_resample.iq", rx_resample_fract); + + printf("run C cmd line chain ...\n"); +% system("cat fsk_demod_resample.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin"); + system("cat fsk_demod_resample.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr convert_f_s16 | ../unittest/tsrc - - 0.9230968 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin"); +% system("cat fsk_demod_resample.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr fractional_decimator_ff 1.08331 | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin"); + f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f); + end + + + if demod_type == 5 + + % C demod with resampler and use C code to measure PER, in this + % test we don't need to run state machine below as C code gives us + % the ouputs we need + + assert(states.tx_real == 0, "need complex signal for this test"); + rx = tx + noise_complex; + SNRdB = 10*log10(var(tx)/var(noise_real)); + + printf("fract resampling ...\n"); + rx_resample_fract = fractional_resample(rx, 1.08331); + save_rtlsdr("fsk_demod_resample.iq", rx_resample_fract); + + % useful for HackRF + %printf("10X resampling ...\n"); + %rx_resample_10M = resample(rx_resample_fract, 10, 1); + %save_rtlsdr("fsk_demod_10M.iq", rx_resample_10M); + + printf("run C cmd line chain - uncoded PER\n"); + system("cat fsk_demod_resample.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr convert_f_s16 | ../unittest/tsrc - - 0.9230968 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - - | ../src/drs232 - /dev/null -v"); + + printf("run C cmd line chain - LDPC coded PER\n"); + system("cat fsk_demod_resample.iq | csdr convert_u8_f | csdr bandpass_fir_fft_cc 0.1 0.4 0.05 | csdr realpart_cf | csdr convert_f_s16 | ../unittest/tsrc - - 0.9230968 | ../build_linux/src/fsk_demod 2XS 8 9600 1200 - - | ../src/drs232_ldpc - /dev/null -v"); + end + + if demod_type == 6 + % C demod with complex input driven simplfied csdr command line, just measure BER of demod + + assert(states.tx_real == 0, "need complex signal for this test"); + rx = tx + noise_complex; + SNRdB = 10*log10(var(tx)/var(noise_real)); + save_rtlsdr("fsk_demod.iq", rx); + system("cat fsk_demod.iq | csdr convert_u8_f | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin C"); + + f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f); + end + + if demod_type == 7 + % C demod with complex input, measure uncoded and uncoded PER + + assert(states.tx_real == 0, "need complex signal for this test"); + rx = tx + noise_complex; + SNRdB = 10*log10(var(tx)/var(noise_real)); + save_rtlsdr("fsk_demod.iq", rx); + + printf("run C cmd line chain - uncoded PER\n"); + system("cat fsk_demod.iq | csdr convert_u8_f | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2X 8 9600 1200 - - C | ../src/drs232 - /dev/null -v"); + + printf("run C cmd line chain - LDPC coded PER\n"); + %system("cat fsk_demod.iq | csdr convert_u8_f | csdr convert_f_s16 | ../build_linux/src/fsk_demod 2XS 8 9600 1200 - - C | ../src/drs232_ldpc - /dev/null -v"); + system("cat fsk_demod.iq | ../build_linux/src/fsk_demod 2XS 8 9600 1200 - - CU8 | ../src/drs232_ldpc - /dev/null -v"); + end + + if (demod_type != 5) && (demod_type != 7) + % state machine. Look for SSTV UW. When found count bit errors over one frame of bits + + state = "wait for uw"; + start_uw_ind = 16*10+1; end_uw_ind = start_uw_ind + 5*10 - 1; + uw_rs232 = tx_codeword(start_uw_ind:end_uw_ind); luw = length(uw_rs232); + start_frame_ind = end_uw_ind + 1; + nbits = length(rx_bit_stream); + uw_thresh = 5; + n_uncoded_errs = 0; + n_uncoded_bits = 0; + n_packets_rx = 0; + last_i = 0; + + % might as well include RS232 framing bits in uncoded error count + + nbits_frame = code_param.data_bits_per_frame*10/8; + + uw_errs = zeros(1, nbits); + for i=luw:nbits + uw_errs(i) = sum(xor(rx_bit_stream(i-luw+1:i), uw_rs232)); + end + + for i=luw:nbits + next_state = state; + if strcmp(state, 'wait for uw') + if uw_errs(i) <= uw_thresh + next_state = 'count errors'; + tx_frame_ind = start_frame_ind; + rx_frame_ind = i + 1; + n_uncoded_errs_this_frame = 0; + %printf("%d %s %s\n", i, state, next_state); + if last_i + printf("i: %d i-last_i: %d ", i, i-last_i); + end + end + end + if strcmp(state, 'count errors') + n_uncoded_errs_this_frame += xor(rx_bit_stream(i), tx_codeword(tx_frame_ind)); + n_uncoded_bits++; + tx_frame_ind++; + if tx_frame_ind == (start_frame_ind+nbits_frame) + n_uncoded_errs += n_uncoded_errs_this_frame; + printf("n_uncoded_errs_this_frame: %d\n", n_uncoded_errs_this_frame); + frame_rx232_rx = rx_bit_stream(rx_frame_ind:rx_frame_ind+nbits_frame-1); + %tx_codeword(start_frame_ind+1:start_frame_ind+10) + %frame_rx232_rx(1:10) + sstv_checksum(frame_rx232_rx); + last_i = i; + n_packets_rx++; + next_state = 'wait for uw'; + end + end + state = next_state; + end + + uncoded_ber = n_uncoded_errs/n_uncoded_bits; + printf("EbNodB: %4.1f SNRdB: %4.1f pkts: %d bits: %d errs: %d BER: %4.3f\n", + EbNodB, SNRdB, n_packets_rx, n_uncoded_bits, n_uncoded_errs, uncoded_ber); + + figure(2); + plot(uw_errs); + title('Unique Word Hamming Distance') + end + +endfunction + + +% Function to test flight mode software. Takes a rx stream of +% demodulated bits, and locates frames using UW detection. Extracts +% data and parity bits. Uses data bits to generate parity bits here +% and compare. + +function compare_parity_bits(rx_bit_stream) + nframes = 500; + + % init LDPC code + + load('H2064_516_sparse.mat'); + HRA = full(HRA); + max_iterations = 100; + decoder_type = 0; + mod_order = 2; + + code_param = ldpc_init(HRA, mod_order); + + % generate frame, this will have random bits not related to + % rx_stream, however we just use it for the UW + + tx_codeword = gen_sstv_frame; + l = length(tx_codeword); + printf("expected rs232 frames codeword length: %d\n", l); + + % state machine. Look for SSTV UW. When found count bit errors over one frame of bits + + state = "wait for uw"; + start_uw_ind = 16*10+1; end_uw_ind = start_uw_ind + 4*10 - 1; + uw_rs232 = tx_codeword(start_uw_ind:end_uw_ind); luw = length(uw_rs232); + start_frame_ind = end_uw_ind + 1; + nbits = nframes*l; + uw_thresh = 5; + n_uncoded_errs = 0; + n_uncoded_bits = 0; + n_packets_rx = 0; + last_i = 0; + + % might as well include RS232 framing bits in uncoded error count + + uw_errs = luw*ones(1, nbits); + for i=luw:nbits + uw_errs(i) = sum(xor(rx_bit_stream(i-luw+1:i), uw_rs232)); + end + + frame_start = find(uw_errs < 2)+1; + nframes = length(frame_start) + for i=1:nframes + + % double check UW OK + + st_uw = frame_start(i) - luw; en_uw = frame_start(i) - 1; + uw_err_check = sum(xor(rx_bit_stream(st_uw:en_uw), uw_rs232)); + %printf("uw_err_check: %d\n", uw_err_check); + + % strip off rs232 start/stop bits + + nbits_rs232 = (256+2+65)*10; + nbits = (256+2+65)*8; + nbits_byte = 10; + rx_codeword = zeros(1,nbits); + pdb = 1; + + for k=1:nbits_byte:nbits_rs232 + for l=1:8 + rx_codeword(pdb) = rx_bit_stream(frame_start(i)-1+k+l); + pdb++; + end + end + assert(pdb == (nbits+1)); + + data_bits = rx_codeword(1:256*8); + checksum_bits = rx_codeword(256*8+1:258*8); + parity_bits = rx_codeword(258*8+1:258*8+516); + padding_bits = rx_codeword(258*8+516+1:258*8+516+1); + + % stopped here as we found bug lol! + end + + figure(1); clf; + plot(uw_errs); + title('Unique Word Hamming Distance') + figure(2); clf; + lframe_start = length(frame_start); + plot(frame_start(2:lframe_start)-frame_start(1:lframe_start-1)); + %title('Unique Word Hamming Distance') + +endfunction + + +% Start simulation -------------------------------------------------------- + +more off; +currentdir = pwd; +thiscomp = computer; + +if strcmpi(thiscomp, 'MACI64')==1 + if exist('CMLSimulate')==0 + cd '/Users/bill/Current/Projects/DLR_FSO/Visit2013_FSO_GEO/cml' + addpath '../' % assume the source files stored here + CmlStartup % note that this is not in the cml path! + disp('added MACI64 path and run CmlStartup') + end +end + +if strfind(thiscomp, 'pc-linux-gnu')==8 + if exist('LdpcEncode')==0, + cd '~/tmp/cml' + CmlStartup + disp('CmlStartup has been run') + % rmpath '/home/bill/cml/mexhelp' % why is this needed? + % maybe different path order in octave cf matlab ? + end +end + +cd(currentdir) + +ldpc_fsk_lib; +randn('state',1); +rand('state',1); + +% ------------------ select which demo/test to run here --------------- + +demo = 12; + +if demo == 1 + printf("simple_ut....\n"); + data = simple_ut; +end + +if demo == 2 + printf("generate C header file....\n"); + data = simple_ut("../src/H2064_516_sparse.h"); +end + +if demo == 3 + printf("decode_from_file ......\n"); + data = simple_ut; + detected_data = decode_from_file("codeword.bin"); + error_positions = xor( detected_data(1:length(data)), data ); + Nerrs = sum(error_positions); + printf(" Nerrs = %d\n", Nerrs); +end + +if demo == 4 + printf("plot a curve....\n"); + plot_curve; +end + +if demo == 5 + + % generate test data and save to disk + + [data code_param] = simple_ut; + f = fopen("dat_in2064.bin","wb"); fwrite(f, data, "uint8"); fclose(f); + + % Outboard C encoder + + system("../src/ldpc_enc dat_in2064.bin dat_op2064.bin"); + + % Test with Octave decoder + + detected_data = decode_from_file("dat_op2064.bin"); + error_positions = xor(detected_data(1:length(data)), data); + Nerrs = sum(error_positions); + printf("Nerrs = %d\n", Nerrs); +end + +if demo == 6 + test_c_encoder; +end + +if demo == 7 + test_c_decoder; +end + +% generates simulated demod soft decision symbols to drive C ldpc decoder with + +if demo == 8 + frames = 100; + EsNodB = 3; + EsNo = 10^(EsNodB/10); + variance = 1/(2*EsNo); + + frame_rs232 = []; + for i=1:frames + frame_rs232 = [frame_rs232 gen_sstv_frame]; + end + + % write hard decn version to disk file, useful for fsk_mod input + + f = fopen("sstv.bin","wb"); fwrite(f, frame_rs232, "char"); fclose(f); + + % soft decision version (with noise) + + s = 1 - 2*frame_rs232; + noise = sqrt(variance)*randn(1,length(frame_rs232)); + r = s + noise; + f = fopen("sstv_sd.bin","wb"); fwrite(f, r, "float32"); fclose(f); +end + + +if demo == 9 + frames = 100; + EbNodB = 11; + + frame_rs232 = []; + for i=1:frames + frame_rs232 = [frame_rs232 gen_sstv_frame]; + end + + % Use C FSK modulator to generate modulated signal + + f = fopen("sstv.bin","wb"); fwrite(f, frame_rs232, "char"); fclose(f); + system("../build_linux/src/fsk_mod 2 9600 1200 1200 2400 sstv.bin fsk_mod.raw"); + + % Add some channel noise here in Octave + + f = fopen("fsk_mod.raw","rb"); tx = fread(f, "short")'; fclose(f); tx_pwr = var(tx); + Fs = 9600; Rs=1200; EbNolin = 10 ^ (EbNodB/10); + variance = (tx_pwr/2)*states.Fs/(states.Rs*EbNolin*states.bitspersymbol); + noise = sqrt(variance)*randn(1,length(tx)); + SNRdB = 10*log10(var(tx)/var(noise)); + rx = tx + noise; + f = fopen("fsk_demod.raw","wb"); tx = fwrite(f, rx, "short"); fclose(f); + + % Demodulate using C modem and C de-framer/LDPC decoder + + system("../build_linux/src/fsk_demod 2XS 8 9600 1200 fsk_demod.raw - | ../src/drs232_ldpc - dummy_out.bin"); +end + + +% Plots uncoded BER curves for two different SSTV simulations. Used +% to compare results with different processing steps as we build up C +% command line. BER curves are powerful ways to confirm system is +% operating as expected, several bugs were found using this system. + +if demo == 10 + sim_in.frames = 10; + EbNodBvec = 7:10; + + sim_in.demod_type = 3; + ber_test1 = []; + for i = 1:length(EbNodBvec) + [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodBvec(i)); + ber_test1(i) = n_uncoded_errs/n_uncoded_bits; + end + + sim_in.demod_type = 4; + ber_c = []; + for i = 1:length(EbNodBvec) + [n_uncoded_errs n_uncoded_bits] = run_sstv_sim(sim_in, EbNodBvec(i)); + ber_test2(i) = n_uncoded_errs/n_uncoded_bits; + end + + figure(1); + clf; + semilogy(EbNodBvec, ber_test1, '+-;first test;') + grid; + xlabel('Eb/No (dB)') + ylabel('BER') + + hold on; + semilogy(EbNodBvec, ber_test2, 'g+-;second test;') + legend("boxoff"); + hold off; + +end + +% Measure PER of complete coded and uncoded system + +if demo == 11 + sim_in.frames = 10; + EbNodB = 9; + sim_in.demod_type = 7; + run_sstv_sim(sim_in, EbNodB); +end + + +% Compare parity bits from an off-air stream of demodulated bits +% Use something like: +% cat ~/Desktop/923096fs_wenet.iq | ../build_linux/src/fsk_demod 2X 8 9600 1200 - fsk_demod.bin CU8 +% (note not soft dec mode) +if demo == 12 + f = fopen("fsk_demod.bin","rb"); rx_bit_stream = fread(f, "uint8")'; fclose(f); + + compare_parity_bits(rx_bit_stream); +end diff --git a/codec2/branches/0.7/octave/test_ml.m b/codec2/branches/0.7/octave/test_ml.m new file mode 100644 index 00000000..a735264b --- /dev/null +++ b/codec2/branches/0.7/octave/test_ml.m @@ -0,0 +1,361 @@ +% test_ml.m +% David Rowe Oct 2014 +% + +% Simulation to test FDM DQPSK with maximum likelihood detection on +% fading channels. Based on JPL publication 89-38 "Multiple Symbol +% Differential Detection of Uncoded and Trellis Coded MPSK" by +% Divsalar, Simon, Shahshahani. Thanks Johhn Gibbs NN7F for advice. + +% reqd to make sure we can repeat tests exactly + +rand('state',1); +randn('state',1); + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + framesize = sim_in.framesize; + ml = sim_in.ml; + + bps = 2; + Nc = Nsymb = framesize/bps; % total number of symbols + + prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc); + prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc); + r = qpsk_mod([0 0])*ones(Nc,4); + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + errors_log = []; + Nerrs_log = []; + + % init HF channel + + hf_n = 1; + + % simulation starts here----------------------------------- + + for nn = 1: Ntrials + + tx_bits = round(rand(1,framesize)); + + % modulate -------------------------------------------- + + for c=1:Nc + tx_symb(c) = qpsk_mod(tx_bits((2*(c-1)+1):(2*c))); + if strcmp(modulation,'dqpsk') + tx_symb(c) *= prev_sym_tx(c); + prev_sym_tx(c) = tx_symb(c); + end + end + s_ch = tx_symb; + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + for c=1:Nc + ahf_model = hf_gain*(spread(hf_n) + exp(-j*c*wsep*nhfdelay)*spread_2ms(hf_n)); + if hf_mag_only + s_ch(c) *= abs(ahf_model); + else + s_ch(c) *= ahf_model; + end + hf_model(hf_n, c) = ahf_model; + end + hf_n++; + end + + tx_symb_log = [tx_symb_log s_ch]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nc) + j*randn(1,Nc)); + + s_ch = s_ch + noise; + + % de-modulate + + rx_bits = zeros(1, framesize); + for c=1:Nc + + r(c,2:4) = r(c, 1:3); + r(c,1) = s_ch(c); + + rx_symb(c) = s_ch(c); + if strcmp(modulation,'dqpsk') + tmp = rx_symb(c); + rx_symb(c) *= conj(prev_sym_rx(c)/abs(prev_sym_rx(c))); + prev_sym_rx(c) = tmp; + end + + if ml == 0 + rx_bits((2*(c-1)+1):(2*c)) = qpsk_demod(rx_symb(c)); + else + tx = [1 j -j -1]; + max_eta = 0; max_symb = tx(1); + for k=1:4 + for k_1=1:4 + for k_2=1:4 + if ml == 3 + eta = abs(r(c,3) + r(c,1)*tx(k)'*tx(k_1)' + r(c,2)*tx(k_1)')^2; + end + if ml == 4 + eta = abs(r(c,4) + r(c,1)*tx(k)'*tx(k_1)'*tx(k_2)' + r(c,2)*tx(k_1)'*tx(k_2)' + r(c,3)*tx(k_2)')^2; + end + %printf(" %d %d %f \n", k_1, k, eta); + if eta > max_eta + max_eta = eta; + max_symb = tx(k); + end + end + end + end + rx_bits((2*(c-1)+1):(2*c)) = qpsk_demod(max_symb); + end + + rx_symb_log = [rx_symb_log rx_symb(c)]; + end + + % Measure BER + + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + av_tx_pwr = (tx_symb_log * tx_symb_log')/length(tx_symb_log); + + printf("EsNo (dB): %3.1f Terrs: %d BER %4.3f QPSK BER theory %4.3f av_tx_pwr: %3.2f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + printf("\n"); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + if hf_sim + figure(3); + clf; + + y = 1:(hf_n-1); + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + mesh(x,y,EsNodBSurface); + grid + axis([1 Nc 1 Rs*5 -5 15]) + title('HF Channel Es/No'); + + if verbose + av_hf_pwr = sum(abs(hf_model(y)).^2)/(hf_n-1); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, hf_n-1); + end + end + + figure(4) + clf + stem(Nerrs_log) + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.Rs = 50; + sim_in.framesize = 8; + sim_in.ml = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; +endfunction + + +function test_curves + + sim_in = standard_init(); + + sim_in.Ntrials = 1000; + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 5:15; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + sim_in.ml = 0; + %sim_dqpsk = ber_test(sim_in, 'dqpsk'); + sim_in.ml = 3; + %sim_dqpsk_ml3 = ber_test(sim_in, 'dqpsk'); + sim_in.ml = 4; + %sim_dqpsk_ml4 = ber_test(sim_in, 'dqpsk'); + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + sim_in.ml = 0; + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.ml = 4; + sim_dqpsk_ml_hf3 = ber_test(sim_in, 'dqpsk'); + sim_in.ml = 4; + sim_dqpsk_ml_hf4 = ber_test(sim_in, 'dqpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + %semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;') + %semilogy(sim_dqpsk_ml3.Ebvec, sim_dqpsk_ml3.BERvec,'k;DQPSK ML N=3 AWGN;') + %semilogy(sim_dqpsk_ml4.Ebvec, sim_dqpsk_ml4.BERvec,'g;DQPSK ML N=4 AWGN;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'c;DQPSK HF;') + semilogy(sim_dqpsk_ml_hf3.Ebvec, sim_dqpsk_ml_hf3.BERvec,'k;DQPSK ML N=3 HF;') + semilogy(sim_dqpsk_ml_hf4.Ebvec, sim_dqpsk_ml_hf4.BERvec,'g;DQPSK ML N=4 HF;') + hold off; + + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + + +function test_single + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + sim_in.Ntrials = 500; + + sim_in.hf_mag_only = 0; + sim_in.hf_sim = 0; + sim_in.ml = 0; + sim_in.Esvec = 10; + + sim_qpsk_hf = ber_test(sim_in, 'dqpsk'); +endfunction + + +% Start simulations --------------------------------------- + +more off; + +test_curves(); +%test_single(); diff --git a/codec2/branches/0.7/octave/test_pilot.m b/codec2/branches/0.7/octave/test_pilot.m new file mode 100644 index 00000000..0117541b --- /dev/null +++ b/codec2/branches/0.7/octave/test_pilot.m @@ -0,0 +1,388 @@ +% test_pilot_.m +% David Rowe Oct 2014 +% + +% Simulation to test pilot assisted coherent FDM QPSK. QPSK performs +% about 4dB better than DQPSK on HF fading channels, even half of that +% would be very useful. + +% reqd to make sure we can repeat tests exactly + +rand('state',1); +randn('state',1); + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_mag_only = sim_in.hf_mag_only; + framesize = sim_in.framesize; + Np = sim_in.Np; + Ns = sim_in.Ns; + coh = sim_in.coh; + + bps = 2; + Nc = Nsymb = framesize/bps; % total number of symbols + + prev_sym_tx = qpsk_mod([0 0])*ones(1,Nc); + prev_sym_rx = qpsk_mod([0 0])*ones(1,Nc); + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; + + tx_symb_log = []; + rx_symb_log = []; + errors_log = []; + Nerrs_log = []; + + % simulation starts here----------------------------------- + + % generate all tx symbols and simulate on HF channel so we can + % use future and past samples for phase estimation. We + % simulate Ntrials+Np so we have enough samples for looking + % forward and backwards for phase estimation + + tx_bits = zeros(Ntrials+Np*Ns, framesize); + tx_symb = zeros(1, Nc); + s_ch = zeros(Ntrials+Np*Ns, Nc); + + for nn = 1: Ntrials+Np*Ns + tx_bits(nn,:) = round(rand(1,framesize)); + + % modulate -------------------------------------------- + + for c=1:Nc + tx_symb(c) = qpsk_mod(tx_bits(nn,(2*(c-1)+1):(2*c))); + if strcmp(modulation,'dqpsk') + tx_symb(c) *= prev_sym_tx(c); + prev_sym_tx(c) = tx_symb(c); + end + end + s_ch(nn,:) = tx_symb; + tx_symb_log = [tx_symb_log tx_symb]; + + if hf_sim + % separation between carriers. Note this effectively + % under samples at Rs, I dont think this matters. + % Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + for c=1:Nc + hf_model(nn,c) = hf_gain*(spread(nn) + exp(-j*c*wsep*nhfdelay)*spread_2ms(nn)); + %hf_model(nn,c) = 1; + if hf_mag_only + s_ch(nn,c) *= abs(hf_model(nn,c)); + else + s_ch(nn,c) *= hf_model(nn,c); + end + end + end + end + + % add channel noise + + noise = sqrt(variance*0.5)*(randn(Ntrials+Np*Ns,Nc) + j*randn(Ntrials+Np*Ns,Nc)); + s_ch += noise; + if hf_sim + hf_model_noise = hf_model + noise; + end + + % phase estimation and demodulation + + phi_ = zeros(Ntrials+Np*Ns, Nc); + + for nn = floor(Np*Ns/2)+1:floor(Np*Ns/2)+Ntrials + + % pilot assisted phase estimation + + if coh + for c=1:Nc + k = 1; + for i = -floor(Np*Ns/2):Ns:floor(Np*Ns/2) + % ignore centre sample as that is the current symbol + if i != 0 + phase_samples(k) = hf_model_noise(nn+i,c); + %printf("i: %d symb phase: %f\n", i, angle(phase_samples(k))); + k++; + end + end + phi_(nn,c) = angle(sum(phase_samples)); + %printf("phi: %f phi_: %f\n", angle(hf_model(nn,c)), phi_(nn,c)); + s_ch(nn,c) *= exp(-j*phi_(nn,c)); + end + end + + % de-modulate + + rx_bits = zeros(1, framesize); + for c=1:Nc + rx_symb(c) = s_ch(nn,c); + if strcmp(modulation,'dqpsk') + tmp = rx_symb(c); + rx_symb(c) *= conj(prev_sym_rx(c)/abs(prev_sym_rx(c))); + prev_sym_rx(c) = tmp; + end + rx_bits((2*(c-1)+1):(2*c)) = qpsk_demod(rx_symb(c)); + rx_symb_log = [rx_symb_log rx_symb(c)]; + end + + % Measure BER + + error_positions = xor(rx_bits, tx_bits(nn,:)); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += framesize; + errors_log = [errors_log error_positions]; + Nerrs_log = [Nerrs_log Nerrs]; + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + + if verbose + av_tx_pwr = (tx_symb_log * tx_symb_log')/length(tx_symb_log); + + printf("EsNo (dB): %3.1f Terrs: %d BER %4.3f QPSK BER theory %4.3f av_tx_pwr: %3.2f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), av_tx_pwr); + printf("\n"); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + sim_out.errors_log = errors_log; + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + title('Scatter plot'); + + if hf_sim + figure(3); + clf; + + y = 1:Ntrials+floor(Np/2); + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + EsNodBSurface(find(EsNodBSurface < -5)) = -5; + mesh(x,y,EsNodBSurface); + grid + axis([1 Nc 1 Rs*5 -5 15]) + title('HF Channel Es/No'); + + if verbose + [m n] = size(hf_model); + av_hf_pwr = sum(sum(abs(hf_model(:,:)).^2))/(m*n); + printf("average HF power: %3.2f over %d symbols\n", av_hf_pwr, m*n); + end + + figure(5); + clf + subplot(211) + [m n] = size(hf_model); + plot(angle(hf_model(1:m,1)),'g;HF channel phase;') + hold on; + plot(phi_(1:m,1),'r+;Estimated HF channel phase;') + ylabel('Phase (rads)'); + subplot(212) + plot(abs(hf_model(1:m,1))) + ylabel('Amplitude'); + xlabel('Time (symbols)'); + end + + figure(4) + clf + stem(Nerrs_log) + + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.Rs = 50; + sim_in.framesize = 8; + sim_in.ml = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 0; +endfunction + + +function test_curves + + sim_in = standard_init(); + + sim_in.Ntrials = 2000; + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 5:15; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + sim_in.coh = 0; + sim_in.Np = 2; + sim_in.Ns = 8; + sim_in.Rs = 100; + + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + sim_in.hf_sim = 1; + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + + sim_in.hf_mag_only = 1; + sim_qpsk_hf_ideal = ber_test(sim_in, 'qpsk'); + sim_in.hf_mag_only = 0; + sim_in.coh = 1; + sim_in.Np = 2; + sim_in.Ns = 4; + sim_in.Rs = 100; + sim_qpsk_hf_coh1 = ber_test(sim_in, 'qpsk'); + sim_in.Np = 4; + sim_in.Ns = 4; + sim_in.Rs = 200; + sim_qpsk_hf_coh2 = ber_test(sim_in, 'qpsk'); + sim_in.Np = 4; + sim_in.Ns = 8; + sim_in.Rs = 200; + sim_qpsk_hf_coh3 = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'k;DQPSK AWGN;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'k;DQPSK HF;') + semilogy(sim_qpsk_hf_ideal.Ebvec, sim_qpsk_hf_ideal.BERvec,'c;QPSK HF ideal;') + semilogy(sim_qpsk_hf_coh1.Ebvec, sim_qpsk_hf_coh1.BERvec,'g;QPSK HF Rs=100 Np=2 Ns=4;') + semilogy(sim_qpsk_hf_coh2.Ebvec, sim_qpsk_hf_coh2.BERvec,'r;QPSK HF Rs=200 Np=4 Ns=4;') + semilogy(sim_qpsk_hf_coh3.Ebvec, sim_qpsk_hf_coh3.BERvec,'b;QPSK HF Rs=200 Np=4 Ns=8;') + hold off; + + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + + +function test_single + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + sim_in.Ntrials = 1000; + + sim_in.hf_mag_only = 0; + sim_in.hf_sim = 1; + sim_in.Esvec = 10; + sim_in.coh = 1; + sim_in.Rs = 100; + sim_in.Np = 2; + sim_in.Ns = 1; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); +endfunction + + +% Start simulations --------------------------------------- + +more off; + +test_curves(); +%test_single(); diff --git a/codec2/branches/0.7/octave/test_qpsk.m b/codec2/branches/0.7/octave/test_qpsk.m new file mode 100644 index 00000000..453302b9 --- /dev/null +++ b/codec2/branches/0.7/octave/test_qpsk.m @@ -0,0 +1,516 @@ +% test_qpsk.m +% David Rowe Feb 2014 +% +% QPSK modem simulation, initially based on code by Bill Cowley +% Generates curves BER versus E/No curves for different modems. +% Design to test coherent demodulation ideas on HF channels without +% building a full blown modem. Uses 'genie provided' estimates for +% timing estimation, frame sync. +% + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + phase_est = sim_in.phase_est; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + Nhfdelay = floor(sim_in.hf_delay_ms*1000/Fs); + hf_phase_only = sim_in.hf_phase_only; + hf_mag_only = sim_in.hf_mag_only; + + bps = 2; + Nsymb = framesize/bps; + prev_sym_tx = qpsk_mod([0 0]); + prev_sym_rx = qpsk_mod([0 0]); + rx_symb_log = []; + + Np = sim_in.Np; % number of pilot symbols to use in phase est + Ns = sim_in.Ns; % spacing of pilot symbols, so (Nps-1) data symbols between every pilot + Nps = Np*Ns; + r_delay_line = zeros(1,Nps+1); + s_delay_line = zeros(1,Nps+1); + spread_main_phi = 0; + spread_delay_phi = 0; + spread_main_phi_log = []; + + ldpc_code = sim_in.ldpc_code; + + if ldpc_code + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + rate = 3/4; + mod_order = 4; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/bps; + else + rate = 1; + end + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % design root nyquist (root raised cosine) filter and init tx and rx filter states + + alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs; + if floor(Fs/Rs) != Fs/Rs + printf("oversampling ratio must be an integer\n"); + return; + end + hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M); + Nfilter = length(hrn); + tx_filter_memory = zeros(1, Nfilter); + rx_filter_memory = zeros(1, Nfilter); + s_delay_line_filt = zeros(1,Nfiltsym); + tx_bits_delay_line_filt = zeros(1,Nfiltsym*bps); + hf_sim_delay_line = zeros(1,M+Nhfdelay); + + for ne = 1:length(Esvec) + Es = Esvec(ne); + EsNo = 10^(Es/10); + + % Given Es/No, determine the variance of a normal noise source: + % + % Es = C/Rs where C is carrier power (energy per unit time) and Rs is the symbole rate + % N = NoB where N is the total noise power, No is the Noise spectral density is W/Hz + % and B is the bandwidth of the noise which is Fs + % No = N/Fs + % + % equating Es/No we get: + % + % Es/No = (C/Rs)/(No/Fs) + % No = CFs/(Rs(Es/No)) + + variance = Fs/(Rs*EsNo); + Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", Es, EsNo, variance); + end + + % init HF channel + sc = 1; + + tx_filt_log = []; + rx_filt_log = []; + rx_baseband_log = []; + tx_baseband_log = []; + noise_log = []; + hf_angle_log = []; + tx_phase = rx_phase = 0; + tx_data_buffer = zeros(1,2*framesize); + s_data_buffer = zeros(1,2*Nsymb); + C_log = []; + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize*rate ) ); + %tx_bits = [1 0 zeros(1,framesize*rate-2)]; + + % modulate + + if ldpc_code + [tx_bits, s] = ldpc_enc(tx_bits, code_param); + t2 = tx_bits; + s2 = s; + else + s = zeros(1, Nsymb); + for i=1:Nsymb + tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + %printf("shift: %f prev_sym: %f ", tx_symb, prev_sym_tx); + if strcmp(modulation,'dqpsk') + tx_symb *= prev_sym_tx; + %printf("tx_symb: %f\n", tx_symb); + prev_sym_tx = tx_symb; + end + s(i) = tx_symb; + end + end + s_ch = s; + + % root nyquist filter symbols + + for k=1:Nsymb + + % tx filter symbols + + tx_filt = zeros(1,M); + + % tx filter each symbol, generate M filtered output samples for each symbol. + % Efficient polyphase filter techniques used as tx_filter_memory is sparse + + tx_filter_memory(Nfilter) = s_ch(k); + + for i=1:M + tx_filt(i) = M*tx_filter_memory(M:M:Nfilter) * hrn(M-i+1:M:Nfilter)'; + end + tx_filter_memory(1:Nfilter-M) = tx_filter_memory(M+1:Nfilter); + tx_filter_memory(Nfilter-M+1:Nfilter) = zeros(1,M); + + % HF channel simulation + + if hf_sim + + hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay); + hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_filt; + + % disable as a wrap around will cause a nasty phase jump. Best to generate + % longer files + %if ((sc+M) > length(spread)) || ((sc+M) > length(spread_2ms)) + % sc =1 ; + %end + comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))'; + if hf_phase_only + tx_filt = tx_filt.*exp(j*angle(comb)); + else + if hf_mag_only + comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))'; + tx_filt = tx_filt.*abs(comb); + else + % regular HF channel sim + tx_filt = tx_filt.*conj(spread(sc:sc+M-1))' + hf_sim_delay_line(1:M).*conj(spread_2ms(sc:sc+M-1))'; + end + end + sc += M; + + % normalise so average HF power C=1 + + if hf_phase_only == 0 % C already 1 if we are just tweaking phase + tx_filt *= hf_gain; + end + C_log = [C_log abs(comb)*hf_gain]; + end + tx_filt_log = [tx_filt_log tx_filt]; + hf_angle_log = [hf_angle_log angle(comb)]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*( randn(1,M) + j*randn(1,M) ); + noise_log = [noise_log noise]; + rx_baseband = tx_filt.*exp(j*phase_offset) + noise; + phase_offset += w_offset; + + % rx filter symbol + + rx_filter_memory(Nfilter-M+1:Nfilter) = rx_baseband; + rx_filt = rx_filter_memory * hrn'; + rx_filter_memory(1:Nfilter-M) = rx_filter_memory(1+M:Nfilter); + rx_filt_log = [rx_filt_log rx_filt]; + + % delay in tx symbols to compensate for filtering + % delay, as tx symbols are used as pilot symbols input + % to phase est + + s_delay_line_filt(1:Nfiltsym-1) = s_delay_line_filt(2:Nfiltsym); + s_delay_line_filt(Nfiltsym) = s(k); + s(k) = s_delay_line_filt(1); + + % delay in tx bits to compensate for filtering delay + + tx_bits_delay_line_filt(1:(Nfiltsym-1)*bps) = tx_bits_delay_line_filt(bps+1:Nfiltsym*bps); + tx_bits_delay_line_filt((Nfiltsym-1)*bps+1:Nfiltsym*bps) = tx_bits((k-1)*bps+1:k*bps); + tx_bits((k-1)*bps+1:k*bps) = tx_bits_delay_line_filt(1:bps); + + s_ch(k) = rx_filt; + end + + % coherent demod phase estimation and correction using pilot symbols + % cheating a bit here, we use fact that all tx-ed symbols are known + + if phase_est + for i=1:Nsymb + + % delay line for phase est window + + r_delay_line(1:Nps-1) = r_delay_line(2:Nps); + r_delay_line(Nps) = s_ch(i); + + % delay in tx data to compensate data for phase est window + + s_delay_line(1:Nps-1) = s_delay_line(2:Nps); + s_delay_line(Nps) = s(i); + tx_bits(2*(i-1)+1:2*i) = qpsk_demod(s_delay_line(floor(Nps/2)+1)); + + % estimate phase from surrounding known pilot symbols and correct + + corr = 0; centre = floor(Nps/2)+1; + for k=1:Ns:(Nps+1) + if (k != centre) + corr += s_delay_line(k) * r_delay_line(k)'; + end + end + s_ch(i) = r_delay_line(centre).*exp(j*angle(corr)); + end + %printf("corr: %f angle: %f\n", corr, angle(corr)); + end + + % de-modulate + + rx_bits = zeros(1, framesize); + for i=1:Nsymb + rx_symb = s_ch(i); + if strcmp(modulation,'dqpsk') + tmp = rx_symb; + rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx)); + prev_sym_rx = tmp; + end + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb); + rx_symb_log = [rx_symb_log rx_symb]; + end + + % Measure BER + + % discard bits from first 2*Nfiltsym+Nps+1 symbols as tx + % and rx filter and phase est memories not full + + skip = bps*(2*Nfiltsym+1+Nps+1); + if nn == 1 + tx_bits_tmp = tx_bits(skip:length(tx_bits)); + rx_bits_tmp = rx_bits(skip:length(rx_bits)); + else + tx_bits_tmp = tx_bits; + rx_bits_tmp = rx_bits; + end + + error_positions = xor( rx_bits_tmp, tx_bits_tmp ); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits_tmp); + + % Optionally LDPC decode + + if ldpc_code + % filter memories etc screw up frame alignment so we need to buffer a frame + + tx_data_buffer(1:framesize) = tx_data_buffer(framesize+1:2*framesize); + s_data_buffer(1:Nsymb) = s_data_buffer(Nsymb+1:2*Nsymb); + tx_data_buffer(framesize+1:2*framesize) = tx_bits; + s_data_buffer(Nsymb+1:2*Nsymb) = s_ch; + + offset = Nfiltsym-1; + if (phase_est) + offset += floor(Nps/2); + end + st_tx = offset*bps+1; + st_s = offset; + + detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ... + s_data_buffer(st_s+1:st_s+Nsymb), min(100,EsNo)); + + % ignore first frame as filter, phase est memories filling up + if nn != 1 + error_positions = xor( detected_data(1:framesize*rate), ... + tx_data_buffer(st_tx:st_tx+framesize*rate-1) ); + Nerrs = sum(error_positions); + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + end + end + + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + if ldpc_code + TERldpcvec(ne) = Terrsldpc; + FERldpcvec(ne) = Ferrsldpc; + BERldpcvec(ne) = Terrsldpc/Tbitsldpc; + end + + if verbose + printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", Es, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2))); + if ldpc_code + printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1)); + end + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_filt_log), var(noise_log), + var(tx_filt_log)/Rs, var(noise_log)/Fs, (var(tx_filt_log)/Rs)/(var(noise_log)/Fs)); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + if ldpc_code + sim_out.BERldpcvec = BERldpcvec; + sim_out.TERldpcvec = TERldpcvec; + sim_out.FERldpcvec = FERldpcvec; + end + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log(2*Nfiltsym:length(rx_symb_log)) .* exp(j*pi/4); + plot(real(scat), imag(scat),'+'); + + figure(3); + clf; + + subplot(211) + plot(C_log); + subplot(212) + plot(hf_angle_log); + axis([1 10000 min(hf_angle_log) max(hf_angle_log)]) + end +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +% Start simulations --------------------------------------- + +more off; +sim_in.verbose = 2; + +sim_in.Esvec = 5; +sim_in.Ntrials = 100; +sim_in.framesize = 100; +sim_in.Rs = 400; +sim_in.phase_offset = 0; +sim_in.phase_est = 0; +sim_in.w_offset = 0; +sim_in.plot_scatter = 1; +sim_in.hf_delay_ms = 2; +sim_in.hf_sim = 1; +sim_in.Np = 6; +sim_in.Ns = 5; +sim_in.hf_phase_only = 0; +sim_in.hf_mag_only = 1; +sim_in.ldpc_code = 0; + +Ebvec = sim_in.Esvec - 10*log10(2); +BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + +sim_qpsk = ber_test(sim_in, 'qpsk'); + +figure(1); +clf; +semilogy(Ebvec, BER_theory,'r;QPSK theory;') +hold on; +semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK;') +hold off; +xlabel('Eb/N0') +ylabel('BER') +grid("minor") + + +if 0 +sim_in.hf_mag_only = 1; +sim_qpsk_mag = ber_test(sim_in, 'qpsk'); + +sim_in.hf_mag_only = 0; +sim_in.hf_phase_only = 1; +sim_in.phase_est = 1; +sim_qpsk_phase = ber_test(sim_in, 'qpsk'); + +sim_in.hf_phase_only = 0; +sim_qpsk_coh_6_5 = ber_test(sim_in, 'qpsk'); + +sim_in.phase_est = 0; +sim_dqpsk = ber_test(sim_in, 'dqpsk'); + +figure(1); +clf; +semilogy(Ebvec, BER_theory,'r;QPSK theory;') +hold on; +semilogy(sim_qpsk_mag.Ebvec, sim_qpsk_mag.BERvec,'g;QPSK CCIR poor mag;') +semilogy(sim_qpsk_phase.Ebvec, sim_qpsk_phase.BERvec,'k;QPSK CCIR poor phase;') +semilogy(sim_qpsk_coh_6_5.Ebvec, sim_qpsk_coh_6_5.BERvec,'c;QPSK CCIR poor Np=6 Ns=5;') +semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'b;DQPSK CCIR poor;') +%semilogy(sim_qpsk_coh_5_24.Ebvec, sim_qpsk_coh_5_24.BERvec,'k;QPSK Ns=5 Np=24;') +%semilogy(sim_qpsk_coh_2_12.Ebvec, sim_qpsk_coh_2_12.BERvec,'c;QPSK Ns=2 Np=12;') +hold off; +xlabel('Eb/N0') +ylabel('BER') +grid("minor") +axis([min(Ebvec)-1 max(Ebvec)+1 1E-2 1]) +end diff --git a/codec2/branches/0.7/octave/test_qpsk2.m b/codec2/branches/0.7/octave/test_qpsk2.m new file mode 100644 index 00000000..978abfa9 --- /dev/null +++ b/codec2/branches/0.7/octave/test_qpsk2.m @@ -0,0 +1,641 @@ +% test_qps2k.m +% David Rowe Feb 2014 +% +% QPSK modem simulation, version 2. Simplifed version of +% test_qpsk. initially based on code by Bill Cowley Generates curves +% BER versus E/No curves for different modems. Design to test +% coherent demodulation ideas on HF channels without building a full +% blown modem. Uses 'genie provided' estimates for timing estimation, +% frame sync. + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + phase_est = sim_in.phase_est; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_phase_only = sim_in.hf_phase_only; + hf_mag_only = sim_in.hf_mag_only; + Nc = sim_in.Nc; + + bps = 2; + Nsymb = framesize/bps; + prev_sym_tx = qpsk_mod([0 0]); + prev_sym_rx = qpsk_mod([0 0]); + + phase_est_method = sim_in.phase_est_method; + if phase_est_method == 1 + Nps = sim_in.Np; + else + Np = sim_in.Np; + Ns = sim_in.Ns; + if Np/2 == floor(Np/2) + printf("Np must be odd\n"); + return; + end + Nps = (Np-1)*Ns+1; + end + r_delay_line = zeros(Nc, Nps); + s_delay_line = zeros(Nc, Nps); + ph_est_log = []; + + phase_noise_amp = sim_in.phase_noise_amp; + + ldpc_code = sim_in.ldpc_code; + + tx_bits_buf = zeros(1,2*framesize); + rx_bits_buf = zeros(1,2*framesize); + rx_symb_buf = zeros(1,2*Nsymb); + + % Init LDPC -------------------------------------------------------------------- + + if ldpc_code + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + rate = sim_in.ldpc_code_rate; + mod_order = 4; + modulation = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/bps; + else + rate = 1; + end + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0; + + tx_symb_log = []; + rx_symb_log = []; + noise_log = []; + mod_strip_log = []; + + % init HF channel + + hf_n = 1; + hf_angle_log = []; + hf_fading = ones(1,Nsymb); % default input for ldpc dec + hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize*rate ) ); + + % modulate -------------------------------------------- + + if ldpc_code + [tx_bits, s] = ldpc_enc(tx_bits, code_param); + else + s = zeros(1, Nsymb); + for i=1:Nsymb + tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i)); + if strcmp(modulation,'dqpsk') + tx_symb *= prev_sym_tx; + prev_sym_tx = tx_symb; + end + s(i) = tx_symb; + end + end + tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize); + tx_bits_buf(framesize+1:2*framesize) = tx_bits; + s_ch = s; + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this is + % effectively under samples at Rs, I dont think this + % matters. Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + if Nsymb/Nc != floor(Nsymb/Nc) + printf("Error: Nsymb/Nc must be an integrer\n") + return; + end + + % arrange symbols in Nsymb/Nc by Nc matrix + + for i=1:Nc:Nsymb + + % Determine HF channel at each carrier for this symbol + + for k=1:Nc + hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n)); + hf_fading(i+k-1) = abs(hf_model(hf_n, k)); + if hf_mag_only + s_ch(i+k-1) *= abs(hf_model(hf_n, k)); + else + s_ch(i+k-1) *= hf_model(hf_n, k); + end + end + hf_n++; + end + end + + tx_symb_log = [tx_symb_log s_ch]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + noise_log = [noise_log noise]; + phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0); + + % organise into carriers to apply frequency and phase offset + + for i=1:Nc:Nsymb + for k=1:Nc + s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1); + end + phase_offset += w_offset; + end + + % phase estimation + + ph_est = zeros(Nc,1); + + if phase_est + + % organise into carriers + + for i=1:Nc:Nsymb + + for k=1:Nc + centre = floor(Nps/2)+1; + + % delay line for phase est window + + r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps); + r_delay_line(k,Nps) = s_ch(i+k-1); + + % delay in tx data to compensate data for phase est window + + s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps); + s_delay_line(k,Nps) = s(i+k-1); + %tx_bits(2*(i+k-1-1)+1:2*(i+k-1)) = qpsk_demod(s_delay_line(k,centre)); + + if phase_est_method == 1 + % QPSK modulation strip and phase est + + mod_strip_pol = angle(r_delay_line(k,:)) * 4; + mod_strip_rect = exp(j*mod_strip_pol); + + ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4; + ph_est(k) = exp(j*ph_est_pol); + + s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol); + else + + % estimate phase from surrounding known pilot symbols and correct + + corr = 0; + for m=1:Ns:Nps + if (m != centre) + corr += s_delay_line(k,m) * r_delay_line(k,m)'; + end + end + ph_est(k) = conj(corr/(1E-6+abs(corr))); + s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr)); + end + + end + + ph_est_log = [ph_est_log ph_est]; + end + %printf("corr: %f angle: %f\n", corr, angle(corr)); + end + + % de-modulate + + rx_bits = zeros(1, framesize); + for i=1:Nsymb + rx_symb = s_ch(i); + if strcmp(modulation,'dqpsk') + tmp = rx_symb; + rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx)); + prev_sym_rx = tmp; + end + rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb); + rx_symb_log = [rx_symb_log rx_symb]; + end + + rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize); + rx_bits_buf(framesize+1:2*framesize) = rx_bits; + rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb); + rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch; + + % determine location of start and end of frame depending on processing delays + + if phase_est + st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2; + st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc; + else + st_rx_bits = 1; + st_rx_symb = 1; + end + en_rx_bits = st_rx_bits+framesize-1; + en_rx_symb = st_rx_symb+Nsymb-1; + + if nn > 1 + % Measure BER + + %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1); + %tx_bits_buf(1:20) + %rx_bits_buf(st_rx_bits:st_rx_bits+20-1) + error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize)); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + + % Optionally LDPC decode + + if ldpc_code + detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading); + %for m=1:20 + % printf("%f ", qpsk_demod(rx_symb_buf(m))); + %end + %detected_data(1:19) + error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) ); + Nerrs = sum(error_positions); + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + end + end + end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + if ldpc_code + TERldpcvec(ne) = Terrsldpc; + FERldpcvec(ne) = Ferrsldpc; + BERldpcvec(ne) = Terrsldpc/Tbitsldpc; + end + + if verbose + printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2))); + if ldpc_code + printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1)); + end + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + if ldpc_code + sim_out.BERldpcvec = BERldpcvec; + sim_out.TERldpcvec = TERldpcvec; + sim_out.FERldpcvec = FERldpcvec; + end + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+'); + title('Scatter plot'); + + figure(3); + clf; + + y = 1:Rs*2; + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + mesh(x,y,EsNodBSurface); + grid + %axis([1 Nc 1 Rs*2 -10 10]) + title('HF Channel Es/No'); + + figure(4); + clf; + %mesh(x,y,unwrap(angle(hf_model(y,:)))); + subplot(211) + plot(y,abs(hf_model(y,1))) + title('HF Channel Carrier 1 Mag'); + subplot(212) + plot(y,angle(hf_model(y,1))) + title('HF Channel Carrier 1 Phase'); + + if phase_est + scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1); + hold on; + plot(angle(scat),'r'); + hold off; + + figure(5) + clf; + scat = ph_est_log(1,y); + plot(real(scat), imag(scat),'+'); + title('Carrier 1 Phase Est'); + axis([-1 1 -1 1]) + end +if 0 + figure(5); + clf; + subplot(211) + plot(real(spread)); + hold on; + plot(imag(spread),'g'); + hold off; + subplot(212) + plot(real(spread_2ms)); + hold on; + plot(imag(spread_2ms),'g'); + hold off; + + figure(6) + tmp = []; + for i = 1:hf_n-1 + tmp = [tmp abs(hf_model(i,:))]; + end + hist(tmp); +end + end + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.framesize = 576; + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_phase_only = 0; + sim_in.hf_mag_only = 1; + + sim_in.phase_est = 0; + sim_in.phase_est_method = 1; + sim_in.Np = 5; + sim_in.Ns = 5; + + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; +endfunction + +function ideal + + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 5; + sim_in.hf_sim = 1; + sim_in.Ntrials = 30; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 2:10; + sim_in.ldpc_code = 0; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + sim_qpsk = ber_test(sim_in, 'qpsk'); + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + + sim_in.hf_sim = 1; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.hf_sim = 0; + sim_qpsk_ldpc = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 1; + sim_qpsk_hf_ldpc = ber_test(sim_in, 'qpsk'); + sim_in.hf_mag_only = 0; + sim_dqpsk_hf_ldpc = ber_test(sim_in, 'dqpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;') + semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;') + semilogy(sim_qpsk_ldpc.Ebvec, sim_qpsk_ldpc.BERldpcvec,'bk;QPSK HF;') + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'g;DQPSK AWGN;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'r;DQPSK HF;') + semilogy(sim_qpsk_hf_ldpc.Ebvec, sim_qpsk_hf_ldpc.BERldpcvec,'b;QPSK HF LDPC 1/2;') + semilogy(sim_dqpsk_hf_ldpc.Ebvec, sim_dqpsk_hf_ldpc.BERldpcvec,'b;DQPSK HF LDPC 1/2;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + +function phase_noise + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 100; + sim_in.Ntrials = 30; + + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_noise_amp = pi/16; + tmp = ber_test(sim_in, 'qpsk'); + + sim_in.plot_scatter = 0; + sim_in.Esvec = 2:8; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + sim_in.phase_noise_amp = 0; + sim_qpsk = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/8; + sim_qpsk_pn8 = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/16; + sim_qpsk_pn16 = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/32; + sim_qpsk_pn32 = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;') + hold on; + semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;') + semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;') + semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;') + + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;') + semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;') + semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;') + semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-2 1]) +endfunction + +function test_phase_est + sim_in = standard_init(); + + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_est = 1; + sim_in.phase_est_method = 2; + sim_in.Np = 3; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 0; + + tmp = ber_test(sim_in, 'qpsk'); + +endfunction + +% Start simulations --------------------------------------- + +more off; + +ideal(); diff --git a/codec2/branches/0.7/octave/test_qpsk3.m b/codec2/branches/0.7/octave/test_qpsk3.m new file mode 100644 index 00000000..447a2059 --- /dev/null +++ b/codec2/branches/0.7/octave/test_qpsk3.m @@ -0,0 +1,957 @@ +% test_qps3k.m +% David Rowe March 2014 +% +% QPSK modem simulation, version 2. Simplifed version of +% test_qpsk. Initially based on code by Bill Cowley Generates curves +% BER versus E/No curves for different modems. Design to test +% coherent demodulation ideas on HF channels without building a full +% blown modem. Uses 'genie provided' estimates for timing estimation, +% frame sync. +% +% Compared to test_qsk2.m this version supports phase estimation +% (coherent demod) + +1; + +% main test function + +function sim_out = ber_test(sim_in, modulation) + Fs = 8000; + + newldpc = sim_in.newldpc; + verbose = sim_in.verbose; + framesize = sim_in.framesize; + Ntrials = sim_in.Ntrials; + Esvec = sim_in.Esvec; + phase_offset = sim_in.phase_offset; + phase_est = sim_in.phase_est; + w_offset = sim_in.w_offset; + plot_scatter = sim_in.plot_scatter; + Rs = sim_in.Rs; + hf_sim = sim_in.hf_sim; + nhfdelay = sim_in.hf_delay_ms*Rs/1000; + hf_phase_only = sim_in.hf_phase_only; + hf_mag_only = sim_in.hf_mag_only; + Nc = sim_in.Nc; + sim_coh_dpsk = sim_in.sim_coh_dpsk; + + bps = 2; + Nsymb = framesize/bps; + for k=1:Nc + prev_sym_tx(k) = qpsk_mod([0 0]); + prev_sym_rx(k) = qpsk_mod([0 0]); + end + + phase_est_method = sim_in.phase_est_method; + if phase_est_method == 2 + Np = sim_in.Np; + Ns = sim_in.Ns; + if Np/2 == floor(Np/2) + printf("Np must be odd\n"); + return; + end + Nps = (Np-1)*Ns+1; + else + Nps = sim_in.Np; + end + r_delay_line = zeros(Nc, Nps); + s_delay_line = zeros(Nc, Nps); + ph_est_log = []; + + phase_noise_amp = sim_in.phase_noise_amp; + + ldpc_code = sim_in.ldpc_code; + + tx_bits_buf = zeros(1,2*framesize); + rx_bits_buf = zeros(1,2*framesize); + rx_symb_buf = zeros(1,2*Nsymb); + hf_fading_buf = zeros(1,2*Nsymb); + + % Init LDPC -------------------------------------------------------------------- + + if ldpc_code + % Start CML library + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + % Our LDPC library + + ldpc; + + rate = sim_in.ldpc_code_rate; + mod_order = 4; + modulation2 = 'QPSK'; + mapping = 'gray'; + + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + code_param = ldpc_init(rate, framesize, modulation2, mod_order, mapping); + code_param.code_bits_per_frame = framesize; + code_param.symbols_per_frame = framesize/bps; + else + rate = 1; + end + + % Init HF channel model from stored sample files of spreading signal ---------------------------------- + + % convert "spreading" samples from 1kHz carrier at Fs to complex + % baseband, generated by passing a 1kHz sine wave through PathSim + % with the ccir-poor model, enabling one path at a time. + + Fc = 1000; M = Fs/Rs; + fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb"); + spread1k = fread(fspread, "int16")/10000; + fclose(fspread); + fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb"); + spread1k_2ms = fread(fspread, "int16")/10000; + fclose(fspread); + + % down convert to complex baseband + spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))'); + spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))'); + + % remove -2000 Hz image + b = fir1(50, 5/Fs); + spread = filter(b,1,spreadbb); + spread_2ms = filter(b,1,spreadbb_2ms); + + % discard first 1000 samples as these were near 0, probably as + % PathSim states were ramping up + + spread = spread(1000:length(spread)); + spread_2ms = spread_2ms(1000:length(spread_2ms)); + + % decimate down to Rs + + spread = spread(1:M:length(spread)); + spread_2ms = spread_2ms(1:M:length(spread_2ms)); + + % Determine "gain" of HF channel model, so we can normalise + % carrier power during HF channel sim to calibrate SNR. I imagine + % different implementations of ccir-poor would do this in + % different ways, leading to different BER results. Oh Well! + + hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms)); + + % Start Simulation ---------------------------------------------------------------- + + for ne = 1:length(Esvec) + EsNodB = Esvec(ne); + EsNo = 10^(EsNodB/10); + + variance = 1/EsNo; + if verbose > 1 + printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance); + end + + Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0; + + tx_symb_log = []; + rx_symb_log = []; + noise_log = []; + mod_strip_log = []; + + % init HF channel + + hf_n = 1; + hf_angle_log = []; + hf_fading = ones(1,Nsymb); % default input for ldpc dec + hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface + + sim_out.errors_log = []; + sim_out.ldpc_errors_log = []; + + for nn = 1: Ntrials + + tx_bits = round( rand( 1, framesize*rate ) ); + + % modulate -------------------------------------------- + + if ldpc_code + [tx_bits, s] = ldpc_enc(tx_bits, code_param); + end + s = zeros(1, Nsymb); + for i=1:Nc:Nsymb + for k=1:Nc + tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1))); + if strcmp(modulation,'dqpsk') + tx_symb *= prev_sym_tx(k); + prev_sym_tx(k) = tx_symb; + end + s(i+k-1) = tx_symb; + end + end + tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize); + tx_bits_buf(framesize+1:2*framesize) = tx_bits; + s_ch = s; + + % HF channel simulation ------------------------------------ + + if hf_sim + + % separation between carriers. Note this is + % effectively under samples at Rs, I dont think this + % matters. Equivalent to doing freq shift at Fs, then + % decimating to Rs. + + wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters + + if Nsymb/Nc != floor(Nsymb/Nc) + printf("Error: Nsymb/Nc must be an integrer\n") + return; + end + + % arrange symbols in Nsymb/Nc by Nc matrix + + for i=1:Nc:Nsymb + + % Determine HF channel at each carrier for this symbol + + for k=1:Nc + hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n)); + hf_fading(i+k-1) = abs(hf_model(hf_n, k)); + if hf_mag_only + s_ch(i+k-1) *= abs(hf_model(hf_n, k)); + else + s_ch(i+k-1) *= hf_model(hf_n, k); + end + end + hf_n++; + end + end + + tx_symb_log = [tx_symb_log s_ch]; + + % AWGN noise and phase/freq offset channel simulation + % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im + + noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb)); + noise_log = [noise_log noise]; + phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0); + + % organise into carriers to apply frequency and phase offset + + for i=1:Nc:Nsymb + for k=1:Nc + s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1); + end + phase_offset += w_offset; + end + + % phase estimation + + ph_est = zeros(Nc,1); + + if phase_est + + % organise into carriers + + for i=1:Nc:Nsymb + + for k=1:Nc + centre = floor(Nps/2)+1; + + % delay line for phase est window + + r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps); + r_delay_line(k,Nps) = s_ch(i+k-1); + + % delay in tx data to compensate data for phase est window + + s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps); + s_delay_line(k,Nps) = s(i+k-1); + + if phase_est_method == 1 + % QPSK modulation strip and phase est + + mod_strip_pol = angle(r_delay_line(k,:)) * 4; + mod_strip_rect = exp(j*mod_strip_pol); + + ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4; + ph_est(k) = exp(j*ph_est_pol); + + s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol); + % s_ch(i+k-1) = r_delay_line(k,centre); + end + + if phase_est_method == 3 + % QPSK modulation strip and phase est with original symbol mags + + mod_strip_pol = angle(r_delay_line(k,:)) * 4; + mod_strip_rect = abs(r_delay_line(k,:)) .* exp(j*mod_strip_pol); + + ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4; + ph_est(k) = exp(j*ph_est_pol); + + s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol); + % s_ch(i+k-1) = r_delay_line(k,centre); + end + + if phase_est_method == 2 + + % estimate phase from surrounding known pilot symbols and correct + + corr = 0; + for m=1:Ns:Nps + if (m != centre) + corr += s_delay_line(k,m) * r_delay_line(k,m)'; + end + end + ph_est(k) = conj(corr/(1E-6+abs(corr))); + s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr)); + %s_ch(i+k-1) = r_delay_line(k,centre); + end + + end + + ph_est_log = [ph_est_log ph_est]; + end + %printf("corr: %f angle: %f\n", corr, angle(corr)); + end + + % de-modulate + + rx_bits = zeros(1, framesize); + for i=1:Nc:Nsymb + for k=1:Nc + rx_symb = s_ch(i+k-1); + if strcmp(modulation,'dqpsk') + tmp = rx_symb; + rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k))); + if sim_coh_dpsk + prev_sym_rx(k) = qpsk_mod(qpsk_demod(tmp)); + else + prev_sym_rx(k) = tmp; + end + s_ch(i+k-1) = rx_symb; + end + rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb); + rx_symb_log = [rx_symb_log rx_symb]; + end + end + +if newldpc + rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize); + rx_bits_buf(framesize+1:2*framesize) = rx_bits; + rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb); + rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch; + hf_fading_buf(1:Nsymb) = hf_fading_buf(Nsymb+1:2*Nsymb); + hf_fading_buf(Nsymb+1:2*Nsymb) = hf_fading; + + % determine location of start and end of frame depending on processing delays + + if phase_est + st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2; + st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc; + else + st_rx_bits = 1; + st_rx_symb = 1; + end + en_rx_bits = st_rx_bits+framesize-1; + en_rx_symb = st_rx_symb+Nsymb-1; + + if nn > 1 + % Measure BER + + %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1); + %tx_bits_buf(1:20) + %rx_bits_buf(st_rx_bits:st_rx_bits+20-1) + error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize)); + Nerrs = sum(error_positions); + sim_out.errors_log = [sim_out.errors_log error_positions]; + Terrs += Nerrs; + Tbits += length(tx_bits); + + % Optionally LDPC decode + + if ldpc_code + detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ... + rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading_buf(1:Nsymb)); + error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) ); + %detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading); + %error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) ); + Nerrs = sum(error_positions); + sim_out.ldpc_errors_log = [sim_out.ldpc_errors_log error_positions]; + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + end + end + +else + error_positions = xor(rx_bits, tx_bits); + Nerrs = sum(error_positions); + Terrs += Nerrs; + Tbits += length(tx_bits); + + % Optionally LDPC decode + + if ldpc_code + detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading); + error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) ); + Nerrs = sum(error_positions); + if Nerrs + Ferrsldpc++; + end + Terrsldpc += Nerrs; + Tbitsldpc += framesize*rate; + + end + end +end + + TERvec(ne) = Terrs; + BERvec(ne) = Terrs/Tbits; + if ldpc_code + TERldpcvec(ne) = Terrsldpc; + FERldpcvec(ne) = Ferrsldpc; + BERldpcvec(ne) = Terrsldpc/Tbitsldpc; + end + + if verbose + printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2))); + if ldpc_code + printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", + Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1)); + end + printf("\n"); + end + if verbose > 1 + printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs, + Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log), + var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log)); + end + end + + Ebvec = Esvec - 10*log10(bps); + + % account for extra power rqd for pilot symbols + + if (phase_est_method == 2) && (phase_est) + Ebvec += 10*log10(Ns/(Ns-1)); + end + + sim_out.BERvec = BERvec; + sim_out.Ebvec = Ebvec; + sim_out.TERvec = TERvec; + if ldpc_code + sim_out.BERldpcvec = BERldpcvec; + sim_out.TERldpcvec = TERldpcvec; + sim_out.FERldpcvec = FERldpcvec; + end + + if plot_scatter + figure(2); + clf; + scat = rx_symb_log .* exp(j*pi/4); + plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+'); + title('Scatter plot'); + + figure(3); + clf; + + y = 1:Rs*2; + x = 1:Nc; + EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance); + mesh(x,y,EsNodBSurface); + grid + %axis([1 Nc 1 Rs*2 -10 10]) + title('HF Channel Es/No'); + + figure(4); + clf; + %mesh(x,y,unwrap(angle(hf_model(y,:)))); + subplot(211) + plot(y,abs(hf_model(y,1))) + title('HF Channel Carrier 1 Mag'); + subplot(212) + plot(y,angle(hf_model(y,1))) + title('HF Channel Carrier 1 Phase'); + + if phase_est + scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1); + hold on; + plot(angle(scat),'r'); + hold off; + + figure(5) + clf; + scat = ph_est_log(1,y); + plot(real(scat), imag(scat),'+'); + title('Carrier 1 Phase Est'); + axis([-1 1 -1 1]) + end +if 0 + figure(5); + clf; + subplot(211) + plot(real(spread)); + hold on; + plot(imag(spread),'g'); + hold off; + subplot(212) + plot(real(spread_2ms)); + hold on; + plot(imag(spread_2ms),'g'); + hold off; + + figure(6) + tmp = []; + for i = 1:hf_n-1 + tmp = [tmp abs(hf_model(i,:))]; + end + hist(tmp); +end + end + +size(sim_out.errors_log) + +endfunction + +% Gray coded QPSK modulation function + +function symbol = qpsk_mod(two_bits) + two_bits_decimal = sum(two_bits .* [2 1]); + switch(two_bits_decimal) + case (0) symbol = 1; + case (1) symbol = j; + case (2) symbol = -j; + case (3) symbol = -1; + endswitch +endfunction + +% Gray coded QPSK demodulation function + +function two_bits = qpsk_demod(symbol) + if isscalar(symbol) == 0 + printf("only works with scalars\n"); + return; + end + bit0 = real(symbol*exp(j*pi/4)) < 0; + bit1 = imag(symbol*exp(j*pi/4)) < 0; + two_bits = [bit1 bit0]; +endfunction + +function sim_in = standard_init + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + sim_in.framesize = 576; + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.phase_noise_amp = 0; + + sim_in.hf_delay_ms = 2; + sim_in.hf_sim = 0; + sim_in.hf_phase_only = 0; + sim_in.hf_mag_only = 1; + + sim_in.phase_est = 0; + sim_in.phase_est_method = 1; + sim_in.Np = 5; + sim_in.Ns = 5; + + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; +endfunction + +function ideal + + sim_in = standard_init(); + + sim_in.sim_coh_dpsk = 0; + sim_in.newldpc = 1; + sim_in.verbose = 2; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 5; + sim_in.hf_sim = 1; + sim_in.Ntrials = 30; + + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + sim_in.hf_sim = 0; + sim_in.plot_scatter = 0; + sim_in.Esvec = 2:15; + sim_in.ldpc_code = 0; + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + sim_qpsk = ber_test(sim_in, 'qpsk'); + sim_dqpsk = ber_test(sim_in, 'dqpsk'); + + sim_in.hf_sim = 1; + sim_in.Esvec = 2:15; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + sim_dqpsk_hf = ber_test(sim_in, 'dqpsk'); + sim_in.ldpc_code = 1; + sim_in.ldpc_code_rate = 3/4; + sim_qpsk_hf_ldpc1 = ber_test(sim_in, 'qpsk'); + sim_in.ldpc_code_rate = 1/2; + sim_qpsk_hf_ldpc2 = ber_test(sim_in, 'qpsk'); + sim_in.ldpc_code_rate = 3/4; + sim_in.hf_sim = 0; + sim_qpsk_awgn_ldpc = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(Ebvec, BER_theory,'r;QPSK theory;') + hold on; + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;') + semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;') + semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;') + semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'m;DQPSK HF;') + semilogy(sim_qpsk_hf_ldpc1.Ebvec, sim_qpsk_hf_ldpc1.BERldpcvec,'k;QPSK HF LDPC 3/4;') + semilogy(sim_qpsk_hf_ldpc2.Ebvec, sim_qpsk_hf_ldpc2.BERldpcvec,'b;QPSK HF LDPC 1/2;') + semilogy(sim_qpsk_awgn_ldpc.Ebvec, sim_qpsk_awgn_ldpc.BERldpcvec,'k;QPSK AWGN LDPC 3/4;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-3 1]) +endfunction + +function phase_noise + sim_in = standard_init(); + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 100; + sim_in.Ntrials = 100; + + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_noise_amp = pi/16; + tmp = ber_test(sim_in, 'qpsk'); + + sim_in.plot_scatter = 0; + sim_in.Esvec = 2:8; + sim_qpsk_hf = ber_test(sim_in, 'qpsk'); + + Ebvec = sim_in.Esvec - 10*log10(2); + BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10))); + + sim_in.phase_noise_amp = 0; + sim_qpsk = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/8; + sim_qpsk_pn8 = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/16; + sim_qpsk_pn16 = ber_test(sim_in, 'qpsk'); + sim_in.phase_noise_amp = pi/32; + sim_qpsk_pn32 = ber_test(sim_in, 'qpsk'); + + figure(1); + clf; + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;') + hold on; + semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;') + semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;') + semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;') + + semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;') + semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;') + semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;') + semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-2 1]) +endfunction + +function phase_est_hf + sim_in = standard_init(); + + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5:15; + sim_in.Ntrials = 100; + + sim_in.newldpc = 1; + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_est = 0; + sim_in.sim_coh_dpsk = 0; + sim_in.phase_est_method = 2; + sim_in.Np = 3; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + + Ebvec = sim_in.Esvec - 10*log10(2); + + baseline = ber_test(sim_in, 'qpsk'); + + sim_in.hf_mag_only = 0; + sim_in.phase_est_method = 2; + sim_in.phase_est = 1; + sim_in.Np = 3; + pilot_3 = ber_test(sim_in, 'qpsk'); + sim_in.Np = 5; + pilot_5 = ber_test(sim_in, 'qpsk'); + sim_in.Np = 7; + pilot_7 = ber_test(sim_in, 'qpsk'); + +if 1 + sim_in.phase_est = 0; + dqpsk = ber_test(sim_in, 'dqpsk'); + + figure(1); + clf; + semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;') + hold on; + semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;') + semilogy(pilot_3.Ebvec, pilot_3.BERvec,'b;QPSK CCIR poor ldpc pilot 3;') + semilogy(pilot_3.Ebvec, pilot_3.BERldpcvec,'b;QPSK CCIR poor ldpc pilot 3;') + semilogy(pilot_5.Ebvec, pilot_5.BERvec,'g;QPSK CCIR poor ldpc pilot 5;') + semilogy(pilot_5.Ebvec, pilot_5.BERldpcvec,'g;QPSK CCIR poor ldpc pilot 5;') + semilogy(pilot_7.Ebvec, pilot_7.BERvec,'m;QPSK CCIR poor ldpc pilot 7;') + semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'m;QPSK CCIR poor ldpc pilot 7;') + semilogy(dqpsk.Ebvec, dqpsk.BERvec,'k;DQPSK CCIR poor ldpc;') + semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'k;DQPSK CCIR poor ldpc;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-2 1]) +end +endfunction + +function phase_est_awgn + sim_in = standard_init(); + + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 0:0.5:3; + sim_in.Ntrials = 30; + + sim_in.newldpc = 1; + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_est = 0; + sim_in.phase_est_method = 1; + sim_in.Np = 3; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 1; + + ideal = ber_test(sim_in, 'qpsk'); + + sim_in.phase_est = 1; + sim_in.Np = 21; + sim_in.phase_est_method = 3; + strip_21_mag = ber_test(sim_in, 'qpsk'); + + sim_in.Np = 41; + strip_41_mag = ber_test(sim_in, 'qpsk'); + + sim_in.phase_est_method = 1; + sim_in.Np = 21; + strip_21 = ber_test(sim_in, 'qpsk'); + + sim_in.Np = 41; + strip_41 = ber_test(sim_in, 'qpsk'); + + sim_in.Np = 7; + sim_in.phase_est_method = 2; + pilot_7 = ber_test(sim_in, 'qpsk'); + + Ebvec = sim_in.Esvec - 10*log10(2); + + figure(1); + clf; + semilogy(ideal.Ebvec, ideal.BERvec,'r;QPSK;') + hold on; + semilogy(ideal.Ebvec, ideal.BERldpcvec,'r;QPSK LDPC;') + semilogy(strip_21.Ebvec, strip_21.BERvec,'g;QPSK strip 21;') + semilogy(strip_21.Ebvec, strip_21.BERldpcvec,'g;QPSK LDPC strip 21;') + semilogy(strip_41.Ebvec, strip_41.BERvec,'b;QPSK strip 41;') + semilogy(strip_41.Ebvec, strip_41.BERldpcvec,'b;QPSK LDPC strip 41;') + semilogy(strip_21_mag.Ebvec, strip_21_mag.BERvec,'m;QPSK strip 21 mag;') + semilogy(strip_21_mag.Ebvec, strip_21_mag.BERldpcvec,'m;QPSK LDPC strip 21 mag;') + semilogy(strip_41_mag.Ebvec, strip_41_mag.BERvec,'c;QPSK strip 41 mag;') + semilogy(strip_41_mag.Ebvec, strip_41_mag.BERldpcvec,'c;QPSK LDPC strip 41 mag;') + semilogy(pilot_7.Ebvec, pilot_7.BERvec,'k;QPSK pilot 7;') + semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'k;QPSK LDPC pilot 7;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-2 1]) +endfunction + +function test_dpsk + sim_in = standard_init(); + + sim_in.Rs = 100; + sim_in.Nc = 8; + + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 5; + sim_in.Ntrials = 30; + + sim_in.newldpc = 1; + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_est = 0; + sim_in.phase_est_method = 3; + sim_in.Np = 41; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.sim_coh_dpsk = 0; + + sim_in.hf_sim = 0; + sim_in.hf_mag_only = 1; + + Ebvec = sim_in.Esvec - 10*log10(2); + + baseline = ber_test(sim_in, 'qpsk'); + sim_in.phase_est = 0; + dqpsk = ber_test(sim_in, 'dqpsk'); + + sim_in.phase_est = 1; + sim_in.phase_est_method = 3; + sim_in.sim_coh_dpsk = 1; + sim_in.Np = 41; + dqpsk_strip_41 = ber_test(sim_in, 'dqpsk'); + + figure(1); + clf; + semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;') + hold on; + semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;') + semilogy(dqpsk.Ebvec, dqpsk.BERvec,'c;DQPSK CCIR poor ldpc;') + semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'c;DQPSK CCIR poor ldpc;') + semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERvec,'m;DQPSK CCIR poor ldpc strip 41;') + semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERldpcvec,'m;DQPSK CCIR poor ldpc strip 41;') + + hold off; + xlabel('Eb/N0') + ylabel('BER') + grid("minor") + axis([min(Ebvec) max(Ebvec) 1E-2 1]) + +endfunction + +function gen_error_pattern_qpsk() + sim_in = standard_init(); + + % model codec and uncoded streams as 1000 bit/s each + + sim_in.Rs = 100; + sim_in.Nc = 4; + + sim_in.verbose = 1; + sim_in.plot_scatter = 0; + + sim_in.Esvec = 10; % Eb/No=2dB + sim_in.Ntrials = 30; + + sim_in.newldpc = 1; + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 1; + + sim_in.phase_est = 1; + sim_in.phase_est_method = 2; + sim_in.Np = 5; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.sim_coh_dpsk = 0; + + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 0; + + qpsk = ber_test(sim_in, 'qpsk'); + + length(qpsk.errors_log) + length(qpsk.ldpc_errors_log) + % multiplex errors into prot and unprot halves of 52 bit codec frames + + error_pattern = []; + for i=1:26:length(qpsk.ldpc_errors_log)-52 + error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) qpsk.errors_log(i:i+25) zeros(1,4)]; + %error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) zeros(1,26) zeros(1,4)]; + %error_pattern = [error_pattern zeros(1,26) qpsk.errors_log(i:i+25) zeros(1,4)]; + end + + fep=fopen("qpsk_errors_2dB.bin","wb"); fwrite(fep, error_pattern, "short"); fclose(fep); + +endfunction + +function gen_error_pattern_dpsk() + sim_in = standard_init(); + + sim_in.Rs = 50; + sim_in.Nc = 16; + + sim_in.verbose = 1; + sim_in.plot_scatter = 1; + + sim_in.Esvec = 10; % Eb/No=Es/No-3 + sim_in.Ntrials = 30; + + sim_in.newldpc = 1; + sim_in.ldpc_code_rate = 1/2; + sim_in.ldpc_code = 0; + + sim_in.phase_est = 0; + sim_in.phase_est_method = 3; + sim_in.Np = 41; + sim_in.phase_offset = 0; + sim_in.w_offset = 0; + sim_in.sim_coh_dpsk = 0; + + sim_in.hf_sim = 1; + sim_in.hf_mag_only = 1; + + dqpsk = ber_test(sim_in, 'dqpsk'); + + fep=fopen("dqpsk_errors_12dB.bin","wb"); fwrite(fep, dqpsk.errors_log, "short"); fclose(fep); + +endfunction + +% Start simulations --------------------------------------- + +more off; + +ideal(); +%phase_est_hf(); +%phase_est_awgn(); +%test_dpsk(); +%gen_error_pattern_qpsk diff --git a/codec2/branches/0.7/octave/tfdmdv.m b/codec2/branches/0.7/octave/tfdmdv.m new file mode 100644 index 00000000..c338fcac --- /dev/null +++ b/codec2/branches/0.7/octave/tfdmdv.m @@ -0,0 +1,306 @@ +% tfdmdv.m +% +% Octave script that tests the C port of the FDMDV modem. This script loads +% the output of unittest/tfdmdv.c and compares it to the output of the +% reference versions of the same functions written in Octave. +% +% Usage: +% +% 1/ In codec2-dev/CMakeLists.txt, ensure set(CMAKE_BUILD_TYPE "Debug"), to +% enable building the C unittests. Build codec2-dev as per +% codec2-dev/README. +% +% 2/ Run the C side from the Octave directory: +% +% codec2-dev/octave$ ../build_linux/unittest/tfdmdv +% codec2-dev/octave$ ls -l tfdmdv_out.txt +% -rw-rw-r-- 1 david david 3419209 Aug 27 10:05 tfdmdv_out.txt +% +% 3/ Run the Octave side (this script): +% +% octave:1> tfdmdv +% + +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +more off +format + +fdmdv; % load modem code +autotest; % automatic testing library + + +% init fdmdv modem states and load up a few constants in this scope for convenience + +f = fdmdv_init; +Nc = f.Nc; +Nb = f.Nb; +M = f.M; +Fs = f.Fs; +P = f.P; +Q = f.Q; + +% Generate reference vectors using Octave implementation of FDMDV modem + +global passes = fails = 0; +frames = 35; +prev_tx_symbols = ones(Nc+1,1); prev_tx_symbols(Nc+1) = 2; +prev_rx_symbols = ones(Nc+1,1); +foff_phase_rect = 1; +channel = []; +channel_count = 0; +next_nin = M; +sig_est = zeros(Nc+1,1); +noise_est = zeros(Nc+1,1); + +sync = 0; +fest_state = 0; +fest_timer = 0; +sync_mem = zeros(1,f.Nsync_mem); + +% Octave outputs we want to collect for comparison to C version + +tx_bits_log = []; +tx_symbols_log = []; +tx_baseband_log = []; +tx_fdm_log = []; +pilot_baseband1_log = []; +pilot_baseband2_log = []; +pilot_lpf1_log = []; +pilot_lpf2_log = []; +S1_log = []; +S2_log = []; +foff_coarse_log = []; +foff_fine_log = []; +foff_log = []; +rx_fdm_filter_log = []; +rx_filt_log = []; +env_log = []; +rx_timing_log = []; +phase_difference_log = []; +rx_symbols_log = []; +rx_bits_log = []; +sync_bit_log = []; +sync_log = []; +nin_log = []; +sig_est_log = []; +noise_est_log = []; + +% adjust this if the screen is getting a bit cluttered + +global no_plot_list = [1 2 3 4 5 6 7 8 12 13 14 15 16]; + +for fr=1:frames + + % modulator + + [tx_bits f] = get_test_bits(f, Nc*Nb); + tx_bits_log = [tx_bits_log tx_bits]; + [tx_symbols f] = bits_to_psk(f, prev_tx_symbols, tx_bits, 'dqpsk'); + prev_tx_symbols = tx_symbols; + tx_symbols_log = [tx_symbols_log tx_symbols]; + [tx_baseband f] = tx_filter(f, tx_symbols); + tx_baseband_log = [tx_baseband_log tx_baseband]; + [tx_fdm f] = fdm_upconvert(f, tx_baseband); + tx_fdm_log = [tx_fdm_log tx_fdm]; + + % channel + + nin = next_nin; + + % nin = M; % when debugging good idea to uncomment this to "open loop" + + channel = [channel real(tx_fdm)]; + channel_count += M; + rx_fdm = channel(1:nin); + channel = channel(nin+1:channel_count); + channel_count -= nin; + + % demodulator -------------------------------------------- + + % shift down to complex baseband + + for i=1:nin + f.fbb_phase_rx = f.fbb_phase_rx*f.fbb_rect'; + rx_fdm(i) = rx_fdm(i)*f.fbb_phase_rx; + end + mag = abs(f.fbb_phase_rx); + f.fbb_phase_rx /= mag; + + % sync = 0; % when debugging good idea to uncomment this to "open loop" + + [pilot prev_pilot f.pilot_lut_index f.prev_pilot_lut_index] = get_pilot(f, f.pilot_lut_index, f.prev_pilot_lut_index, nin); + [foff_coarse S1 S2 f] = rx_est_freq_offset(f, rx_fdm, pilot, prev_pilot, nin, !sync); + + if sync == 0 + foff = foff_coarse; + end + foff_coarse_log = [foff_coarse_log foff_coarse]; + + pilot_baseband1_log = [pilot_baseband1_log f.pilot_baseband1]; + pilot_baseband2_log = [pilot_baseband2_log f.pilot_baseband2]; + pilot_lpf1_log = [pilot_lpf1_log f.pilot_lpf1]; + pilot_lpf2_log = [pilot_lpf2_log f.pilot_lpf2]; + S1_log = [S1_log S1]; + S2_log = [S2_log S2]; + + foff_rect = exp(j*2*pi*foff/Fs); + + for i=1:nin + foff_phase_rect *= foff_rect'; + rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect; + end + + [rx_fdm_filter f] = rxdec_filter(f, rx_fdm_fcorr, nin); + [rx_filt f] = down_convert_and_rx_filter(f, rx_fdm_filter, nin, M/Q); + #{ + for i=1:5 + printf("[%d] rx_fdm_fcorr: %f %f rx_fdm_filter: %f %f\n", i, + real(rx_fdm_fcorr(i)), imag(rx_fdm_fcorr(i)), real(rx_fdm_filter(i)), imag(rx_fdm_filter(i))); + end + for i=1:5 + printf("[%d] rx_fdm_fcorr: %f %f rxdec_lpf_mem: %f %f\n", i, + real(rx_fdm_fcorr(i)), imag(rx_fdm_fcorr(i)), real(f.rxdec_lpf_mem(i)), imag(f.rxdec_lpf_mem(i))); + end + #} + rx_filt_log = [rx_filt_log rx_filt]; + rx_fdm_filter_log = [rx_fdm_filter_log rx_fdm_filter]; + + [rx_symbols rx_timing env f] = rx_est_timing(f, rx_filt, nin); + env_log = [env_log env]; + rx_timing_log = [rx_timing_log rx_timing]; + rx_symbols_log = [rx_symbols_log rx_symbols]; + + next_nin = M; + if rx_timing > 2*M/P + next_nin += M/P; + end + if rx_timing < 0; + next_nin -= M/P; + end + nin_log = [nin_log nin]; + + [rx_bits sync_bit foff_fine pd] = psk_to_bits(f, prev_rx_symbols, rx_symbols, 'dqpsk'); + phase_difference_log = [phase_difference_log pd]; + + foff_fine_log = [foff_fine_log foff_fine]; + foff -= 0.5*foff_fine; + foff_log = [foff_log foff]; + + [sig_est noise_est] = snr_update(f, sig_est, noise_est, pd); + sig_est_log = [sig_est_log sig_est]; + noise_est_log = [noise_est_log noise_est]; + + prev_rx_symbols = rx_symbols; + rx_bits_log = [rx_bits_log rx_bits]; + sync_bit_log = [sync_bit_log sync_bit]; + + % freq est state machine + + [sync reliable_sync_bit fest_state fest_timer sync_mem] = freq_state(f, sync_bit, fest_state, fest_timer, sync_mem); + sync_log = [sync_log sync]; +end + +% Compare to the output from the C version + +load tfdmdv_out.txt + + +% --------------------------------------------------------------------------------------- +% Plot output and test each C function +% --------------------------------------------------------------------------------------- + +% fdmdv_get_test_bits() & bits_to_dqpsk_symbols() + +n = 28; +stem_sig_and_error(1, 211, tx_bits_log_c(1:n), tx_bits_log(1:n) - tx_bits_log_c(1:n), 'tx bits', [1 n -1.5 1.5]) +stem_sig_and_error(1, 212, real(tx_symbols_log_c(1:n/2)), real(tx_symbols_log(1:n/2) - tx_symbols_log_c(1:n/2)), 'tx symbols real', [1 n/2 -1.5 1.5]) + +% fdm_upconvert() + +plot_sig_and_error(3, 211, real(tx_fdm_log_c), real(tx_fdm_log - tx_fdm_log_c), 'tx fdm real') +plot_sig_and_error(3, 212, imag(tx_fdm_log_c), imag(tx_fdm_log - tx_fdm_log_c), 'tx fdm imag') + +% generate_pilot_lut() + +plot_sig_and_error(4, 211, real(pilot_lut_c), real(f.pilot_lut - pilot_lut_c), 'pilot lut real') +plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(f.pilot_lut - pilot_lut_c), 'pilot lut imag') + +% rx_est_freq_offset() + +st=1; en = 5*f.Npilotbaseband; +plot_sig_and_error(5, 211, real(pilot_baseband1_log(st:en)), real(pilot_baseband1_log(st:en) - pilot_baseband1_log_c(st:en)), 'pilot baseband1 real' ) +plot_sig_and_error(5, 212, real(pilot_baseband2_log(st:en)), real(pilot_baseband2_log(st:en) - pilot_baseband2_log_c(st:en)), 'pilot baseband2 real' ) + +st=1; en = 5*f.Npilotlpf; +plot_sig_and_error(6, 211, real(pilot_lpf1_log(st:en)), real(pilot_lpf1_log(st:en) - pilot_lpf1_log_c(st:en)), 'pilot lpf1 real' ) +plot_sig_and_error(6, 212, real(pilot_lpf2_log(st:en)), real(pilot_lpf2_log(st:en) - pilot_lpf2_log_c(st:en)), 'pilot lpf2 real' ) + +plot_sig_and_error(7, 211, real(S1_log), real(S1_log - S1_log_c), 'S1 real' ) +plot_sig_and_error(7, 212, imag(S1_log), imag(S1_log - S1_log_c), 'S1 imag' ) + +plot_sig_and_error(8, 211, real(S2_log), real(S2_log - S2_log_c), 'S2 real' ) +plot_sig_and_error(8, 212, imag(S2_log), imag(S2_log - S2_log_c), 'S2 imag' ) + +plot_sig_and_error(9, 211, foff_coarse_log, foff_coarse_log - foff_coarse_log_c, 'Coarse Freq Offset' ) +plot_sig_and_error(9, 212, foff_fine_log, foff_fine_log - foff_fine_log_c, 'Fine Freq Offset' ) + +plot_sig_and_error(10, 211, foff_log, foff_log - foff_log_c, 'Freq Offset' ) +plot_sig_and_error(10, 212, sync_log, sync_log - sync_log_c, 'Sync & Freq Est Coarse(0) Fine(1)', [1 frames -1.5 1.5] ) + +plot_sig_and_error(11, 211, real(rx_fdm_filter_log), real(rx_fdm_filter_log - rx_fdm_filter_log_c), 'Rx dec filter real' ) +plot_sig_and_error(11, 212, imag(rx_fdm_filter_log), imag(rx_fdm_filter_log - rx_fdm_filter_log_c), 'Rx dec filter imag' ) + +c=1; +plot_sig_and_error(12, 211, real(rx_filt_log(c,:)), real(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt real' ) +plot_sig_and_error(12, 212, imag(rx_filt_log(c,:)), imag(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt imag' ) + +st=1*28; +en = 3*28; +plot_sig_and_error(14, 211, rx_timing_log, rx_timing_log - rx_timing_log_c, 'Rx Timing' ) +stem_sig_and_error(14, 212, sync_bit_log_c, sync_bit_log - sync_bit_log_c, 'Sync bit', [1 n -1.5 1.5]) + +stem_sig_and_error(15, 211, rx_bits_log_c(st:en), rx_bits_log(st:en) - rx_bits_log_c(st:en), 'RX bits', [1 en-st -1.5 1.5]) +stem_sig_and_error(15, 212, nin_log_c, nin_log - nin_log_c, 'nin') + +c = 12; +plot_sig_and_error(16, 211, sig_est_log(c,:), sig_est_log(c,:) - sig_est_log_c(c,:), 'sig est for SNR' ) +plot_sig_and_error(16, 212, noise_est_log(c,:), noise_est_log(c,:) - noise_est_log_c(c,:), 'noise est for SNR' ) + +fr=12; + +stem_sig_and_error(13, 211, real(rx_symbols_log(:,fr)), real(rx_symbols_log(:,fr) - rx_symbols_log_c(:,fr)), 'rx symbols real' ) +stem_sig_and_error(13, 212, imag(rx_symbols_log(:,fr)), imag(rx_symbols_log(:,fr) - rx_symbols_log_c(:,fr)), 'rx symbols imag' ) + +stem_sig_and_error(17, 211, real(phase_difference_log(:,fr)), real(phase_difference_log(:,fr) - phase_difference_log_c(:,fr)), 'phase difference real' ) +stem_sig_and_error(17, 212, imag(phase_difference_log(:,fr)), imag(phase_difference_log(:,fr) - phase_difference_log_c(:,fr)), 'phase difference imag' ) + + +check(tx_bits_log, tx_bits_log_c, 'tx_bits'); +check(tx_symbols_log, tx_symbols_log_c, 'tx_symbols'); +check(tx_fdm_log, tx_fdm_log_c, 'tx_fdm'); +check(f.pilot_lut, pilot_lut_c, 'pilot_lut'); +check(f.pilot_coeff, pilot_coeff_c, 'pilot_coeff'); +check(pilot_baseband1_log, pilot_baseband1_log_c, 'pilot lpf1'); +check(pilot_baseband2_log, pilot_baseband2_log_c, 'pilot lpf2'); +check(S1_log, S1_log_c, 'S1'); +check(S2_log, S2_log_c, 'S2'); +check(foff_coarse_log, foff_coarse_log_c, 'foff_coarse'); +check(foff_fine_log, foff_fine_log_c, 'foff_fine'); +check(foff_log, foff_log_c, 'foff'); +check(rx_fdm_filter_log, rx_fdm_filter_log_c, 'rxdec filter'); +check(rx_filt_log, rx_filt_log_c, 'rx filt', 2E-3); +check(env_log, env_log_c, 'env'); +check(rx_timing_log, rx_timing_log_c, 'rx_timing'); +check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols', 2E-3); +check(rx_bits_log, rx_bits_log_c, 'rx bits'); +check(sync_bit_log, sync_bit_log_c, 'sync bit'); +check(sync_log, sync_log_c, 'sync'); +check(nin_log, nin_log_c, 'nin'); +check(sig_est_log, sig_est_log_c, 'sig_est'); +check(noise_est_log, noise_est_log_c, 'noise_est'); +printf("\npasses: %d fails: %d\n", passes, fails); diff --git a/codec2/branches/0.7/octave/tfmfsk.m b/codec2/branches/0.7/octave/tfmfsk.m new file mode 100644 index 00000000..342f800d --- /dev/null +++ b/codec2/branches/0.7/octave/tfmfsk.m @@ -0,0 +1,497 @@ +% tfsk.m +% Author: Brady O'Brien 8 February 2016 + + + +% Copyright 2016 David Rowe +% +% All rights reserved. +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License version 2, as +% published by the Free Software Foundation. This program is +% distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +% License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with this program; if not, see . + + +% Octave script to check c port of mancyfsk/fmfsk against the fmfsk.m +% +#{ + + FMFSK Modem automated test instructions: + + 1. Use cmake to build in debug mode to ensure unittest/tfsk is built: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ cmake -DCMAKE_BUILD_TYPE=Debug .. + $ make + + 2 - Change tfsk_location below if required + 3 - Ensure Octave packages signal and parallel are installed + 4 - Start Octave and run tfsk.m. It will perform all tests automatically + +#} + +%tfsk executable path/file +global tfsk_location = '../build_linux/unittest/tfmfsk'; + +%Set to 1 for verbose printouts +global print_verbose = 0; + + + +fmfsk +pkg load signal; +pkg load parallel; +graphics_toolkit('gnuplot'); + + +global mod_pass_fail_maxdiff = 1e-3/5000; + +function mod = fmfsk_mod_c(Fs,Rs,bits) + global tfsk_location; + %command to be run by system to launch the modulator + command = sprintf('%s M %d %d fsk_mod_ut_bitvec fsk_mod_ut_modvec fmfsk_mod_ut_log.txt',tfsk_location,Fs,Rs); + %save input bits into a file + bitvecfile = fopen('fsk_mod_ut_bitvec','wb+'); + fwrite(bitvecfile,bits,'uint8'); + fclose(bitvecfile); + + %run the modulator + system(command); + + modvecfile = fopen('fsk_mod_ut_modvec','rb'); + mod = fread(modvecfile,'single'); + fclose(modvecfile); + +endfunction + + +%Compare 2 vectors, fail if they are not close enough +function pass = vcompare(vc,voct,vname,tname,tol,pnum) + global print_verbose; + + %Get delta of vectors + dvec = abs(abs(vc)-abs(voct)); + + %Normalize difference + dvec = dvec ./ abs(max(abs(voct))+1e-8); + + maxdvec = abs(max(dvec)); + pass = maxdvec=states.nin + ninold = states.nin; + [bitbuf,states] = fmfsk_demod(states, modin(1:states.nin)); + modin=modin(ninold+1:length(modin)); + obits = [obits bitbuf]; + + o_norm_rx_timing = [o_norm_rx_timing states.norm_rx_timing]; + o_symsamp = [o_symsamp states.symsamp]; + o_rx_filt = [o_rx_filt states.rx_filt]; + + end + + close all + pass = 1; + + % One part-per-thousand allowed on important parameters + + pass = vcompare(t_rx_filt,o_rx_filt,'rx filt',tname,.001,8) && pass; + pass = vcompare(t_norm_rx_timing,o_norm_rx_timing,'norm rx timing',tname,.001,9) && pass; + pass = vcompare(t_symsamp,o_symsamp,'symsamp',tname,.001,10) && pass; + + assert(pass); + diffpass = sum(xor(obits,bits'))<4; + diffbits = sum(xor(obits,bits')); + + + if diffpass==0 + printf('\n***bitcompare test failed test %s diff %d\n\n',tname,sum(xor(obits,bits'))) + figure(15) + plot(xor(obits,bits')) + title(sprintf('Bitcompare failure test %s',tname)) + end + + pass = pass && diffpass; + + + test_stats.pass = pass; + test_stats.diff = sum(xor(obits,bits')); + test_stats.cbits = bits'; + test_stats.obits = obits; + +endfunction + +function [dmod,cmod,omod,pass] = fmfsk_mod_test(Fs,Rs,bits,tname,M=2) + global mod_pass_fail_maxdiff; + %Run the C modulator + cmod = fmfsk_mod_c(Fs,Rs,bits); + %Set up and run the octave modulator + states.M = M; + states = fmfsk_init(Fs,Rs); + + + omod = fmfsk_mod(states,bits)'; + + dmod = cmod-omod; + pass = max(dmod)<(mod_pass_fail_maxdiff*length(dmod)); + if !pass + printf('Mod failed test %s!\n',tname); + end +endfunction + +% Random bit modulator test +% Pass random bits through the modulators and compare +function pass = test_mod_fdvbcfg_randbits + rand('state',1); + randn('state',1); + bits = rand(1,19200)>.5; + [dmod,cmod,omod,pass] = fmfsk_mod_test(48000,2400,bits,"mod fdvbcfg randbits"); + + if(!pass) + figure(1) + plot(dmod) + title("Difference between octave and C mod impl"); + end + +endfunction + +% run_sim copypasted from fsk_horus.m +% simulation of tx and rx side, add noise, channel impairments ---------------------- + +function stats = tfmfsk_run_sim(EbNodB,timing_offset=0,de=0,of=0,hpf=0,df=0,M=2) + global print_verbose; + test_frame_mode = 2; + frames = 70; + %EbNodB = 3; + %timing_offset = 0.0; % see resample() for clock offset below + %fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + + more off + rand('state',1); + randn('state',1); + + Fs = 48000; + Rbit = 2400; + + % ---------------------------------------------------------------------- + + fm_states.pre_emp = 0; + fm_states.de_emp = de; + fm_states.Ts = Fs/(Rbit*2); + fm_states.Fs = Fs; + fm_states.fc = Fs/4; + fm_states.fm_max = 3E3; + fm_states.fd = 5E3; + fm_states.output_filter = of; + fm_states = analog_fm_init(fm_states); + + % ---------------------------------------------------------------------- + + states = fmfsk_init(Fs,Rbit); + + states.verbose = 0x1; + Rs = states.Rs; + nsym = states.nsym; + Fs = states.Fs; + nbit = states.nbit; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rb*EbNo); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nbit)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nbit*(frames+1))); + end + if test_frame_mode == 3 + % repeating sequence of all symbols + % great for initial test of demod if nothing else works, + % look for this pattern in rx_bits + + % ...10101... + tx_bits = zeros(1, states.nbit*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + + end + + [b, a] = cheby1(4, 1, 300/Fs, 'high'); % 300Hz HPF to simulate FM radios + + tx_pmod = fmfsk_mod(states, tx_bits); + + tx = analog_fm_mod(fm_states, tx_pmod); + + if(timing_offset>0) + tx = resample(tx, 2000, 1999); % simulated 1000ppm sample clock offset + end + + %Add frequency drift + fdrift = df/Fs; + fshift = 2*pi*fdrift*(1:length(tx)); + fshift = exp(j*(fshift.^2)); + tx = tx.*fshift; + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise'; + + %Demod by analog fm + rx = analog_fm_demod(fm_states, rx); + + %High-pass filter to simulate the FM radios + if hpf>0 + rx = filter(b,a,rx); + end + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,2*nbit); + + test_name = sprintf("tfmfsk run sim EbNodB:%d frames:%d timing_offset:%d df:%d",EbNodB,frames,timing_offset,df); + tstats = fmfsk_demod_xt(Fs,Rbit,rx',test_name,M); + + pass = tstats.pass; + obits = tstats.obits; + cbits = tstats.cbits; + + % Figure out BER of octave and C modems + bitcnt = length(tx_bits); + rx_bits = obits; + ber = 1; + ox = 1; + for offset = (1:400) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + bero = ber; + ber = 1; + rx_bits = cbits; + ox = 1; + for offset = (1:400) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + berc = ber; + + if print_verbose == 1 + printf("C BER %f in test %s\n",berc,test_name); + printf("Oct BER %f in test %s\n",bero,test_name); + end + + stats.berc = berc; + stats.bero = bero; + stats.name = test_name; + % non-coherent BER theory calculation + % It was complicated, so I broke it up + + ms = 2; + ns = (1:ms-1); + as = (-1).^(ns+1); + bs = (as./(ns+1)); + + cs = ((ms-1)./ns); + + ds = ns.*log2(ms); + es = ns+1; + fs = exp( -(ds./es)*EbNo ); + + thrncoh = ((ms/2)/(ms-1)) * sum(bs.*((ms-1)./ns).*exp( -(ds./es)*EbNo )); + + stats.thrncoh = thrncoh; + stats.pass = pass; + endfunction + + +function pass = ebno_battery_test(timing_offset,drift,hpf,deemp,outfilt) + global print_verbose; + %Range of EbNodB over which to test + ebnodbrange = (8:2:20); + ebnodbs = length(ebnodbrange); + + %Replication of other parameters for parcellfun + timingv = repmat(timing_offset ,1,ebnodbs); + driftv = repmat(drift ,1,ebnodbs); + hpfv = repmat(hpf ,1,ebnodbs); + deempv = repmat(deemp ,1,ebnodbs); + outfv = repmat(outfilt ,1,ebnodbs); + + statv = pararrayfun(floor(.75*nproc()),@tfmfsk_run_sim,ebnodbrange,timingv,deempv,outfv,hpfv,driftv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv); + + passv = zeros(1,length(statv)); + for ii=(1:length(statv)) + passv(ii)=statv(ii).pass; + if statv(ii).pass + printf("Test %s passed\n",statv(ii).name); + else + printf("Test %s failed\n",statv(ii).name); + end + end + + %All pass flags are '1' + pass = sum(passv)>=length(passv); + %and no tests died + pass = pass && length(passv)==ebnodbs; + passv; + assert(pass) +endfunction + +%Test with and without sample clock offset +function pass = test_timing_var(drift,hpf,deemp,outfilt) + pass = ebno_battery_test(1,drift,hpf,deemp,outfilt) + assert(pass) + pass = ebno_battery_test(0,drift,hpf,deemp,outfilt) + assert(pass) +endfunction + +%Test with and without 1 Hz/S freq drift +function pass = test_drift_var(hpf,deemp,outfilt) + pass = test_timing_var(1,hpf,deemp,outfilt) + assert(pass) + pass = pass && test_timing_var(0,hpf,deemp,outfilt) + assert(pass) +endfunction + +function pass = test_fmfsk_battery() + pass = test_mod_fdvbcfg_randbits; + assert(pass) + pass = pass && test_drift_var(1,1,1); + assert(pass) + if pass + printf("***** All tests passed! *****\n"); + end +endfunction + +function plot_fmfsk_bers(M=2) + %Range of EbNodB over which to test + ebnodbrange = (8:14); + ebnodbs = length(ebnodbrange); + + %Replication of other parameters for parcellfun + %Turn on all of the impairments + timingv = repmat(1 ,1,ebnodbs); + driftv = repmat(1 ,1,ebnodbs); + hpfv = repmat(1 ,1,ebnodbs); + deempv = repmat(1 ,1,ebnodbs); + outfv = repmat(1 ,1,ebnodbs); + + statv = pararrayfun(nproc(),@tfmfsk_run_sim,ebnodbrange,timingv,deempv,outfv,hpfv,driftv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv); + + for ii = (1:length(statv)) + stat = statv(ii); + berc(ii)=stat.berc; + bero(ii)=stat.bero; + berinc(ii)=stat.thrncoh; + end + clf; + figure(M) + + semilogy(ebnodbrange, berinc,sprintf('r;2FSK non-coherent theory;',M)) + hold on; + semilogy(ebnodbrange, bero ,sprintf('g;Octave ME-FM-FSK Demod;',M)) + semilogy(ebnodbrange, berc,sprintf('v;C ME-FM-FSK Demod;',M)) + hold off; + grid("minor"); + axis([min(ebnodbrange) max(ebnodbrange) 1E-5 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + +endfunction + +xpass = test_fmfsk_battery +plot_fmfsk_bers(2) + +if xpass + printf("***** All tests passed! *****\n"); +else + printf("***** Some test failed! Look back thorugh output to find failed test *****\n"); +end diff --git a/codec2/branches/0.7/octave/tfsk.m b/codec2/branches/0.7/octave/tfsk.m new file mode 100644 index 00000000..0f2d401a --- /dev/null +++ b/codec2/branches/0.7/octave/tfsk.m @@ -0,0 +1,630 @@ +% tfsk.m +% Author: Brady O'Brien 8 January 2016 + + + +% Copyright 2016 David Rowe +% +% All rights reserved. +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License version 2, as +% published by the Free Software Foundation. This program is +% distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +% License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with this program; if not, see . + + +% Octave script to check c port of fsk_horus against the fsk_horus.m +% +% [X] - Functions to wrap around fsk_mod and fsk_demod executables +% [X] - fsk_mod +% [X] - fsk_demod +% [X] - Functions to wrap around octave and c implementations, pass +% same dataset, compare outputs, and give clear go/no-go +% [X] - fsk_mod_test +% [X] - fsk_demod_test +% [X] - Port of run_sim and EbNodB curve test battery +% [X] - Extract and compare more parameters from demod +% [X] - Run some tests in parallel + +#{ + + FSK Modem automated test instructions: + + 1. Use cmake to build in debug mode to ensure unittest/tfsk is built: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ cmake -DCMAKE_BUILD_TYPE=Debug .. + $ make + + 2 - Change tfsk_location below if required + 3 - Ensure Octave packages signal and parallel are installed + 4 - Start Octave and run tfsk.m. It will perform all tests automatically + +#} + +%tfsk executable path/file +global tfsk_location = '../build_linux/unittest/tfsk'; + +%Set to 1 for verbose printouts +global print_verbose = 0; + + +fsk_horus_as_a_lib = 1; % make sure calls to test functions at bottom are disabled +%fsk_horus_2fsk; +fsk_horus +pkg load signal; +pkg load parallel; +graphics_toolkit('gnuplot'); + + +global mod_pass_fail_maxdiff = 1e-3/5000; + +function mod = fsk_mod_c(Fs,Rs,f1,fsp,bits,M) + global tfsk_location; + %command to be run by system to launch the modulator + command = sprintf('%s M %d %d %d %d %d fsk_mod_ut_bitvec fsk_mod_ut_modvec fsk_mod_ut_log.txt',tfsk_location,M,f1,fsp,Fs,Rs); + %save input bits into a file + bitvecfile = fopen('fsk_mod_ut_bitvec','wb+'); + fwrite(bitvecfile,bits,'uint8'); + fclose(bitvecfile); + + %run the modulator + system(command); + + modvecfile = fopen('fsk_mod_ut_modvec','rb'); + mod = fread(modvecfile,'single'); + fclose(modvecfile); + +endfunction + + +%Compare 2 vectors, fail if they are not close enough +function pass = vcompare(vc,voct,vname,tname,tol,pnum) + global print_verbose; + %Get delta of vectors + dvec = abs(abs(vc)-abs(voct)); + + %Normalize difference + dvec = dvec ./ abs(max(abs(voct))+1e-8); + + maxdvec = abs(max(dvec)); + pass = maxdvec=states.nin + ninold = states.nin; + states = est_freq(states, modin(1:states.nin), states.M); + [bitbuf,states] = fsk_horus_demod(states, modin(1:states.nin)); + modin=modin(ninold+1:length(modin)); + obits = [obits bitbuf]; + + %Save other parameters + o_f1_dc = [o_f1_dc states.f_dc(1,1:states.Nmem-Ts/P)]; + o_f2_dc = [o_f2_dc states.f_dc(2,1:states.Nmem-Ts/P)]; + o_f1_int = [o_f1_int states.f_int(1,:)]; + o_f2_int = [o_f2_int states.f_int(2,:)]; + o_EbNodB = [o_EbNodB states.EbNodB]; + o_ppm = [o_ppm states.ppm]; + o_rx_timing = [o_rx_timing states.rx_timing]; + o_norm_rx_timing = [o_norm_rx_timing states.norm_rx_timing]; + o_Sf = [o_Sf states.Sf']; + o_f1 = [o_f1 states.f(1)]; + o_f2 = [o_f1 states.f(2)]; + o_fest = [o_fest states.f]; + o_nin = [o_nin states.nin]; + if M==4 + o_f3_dc = [o_f3_dc states.f_dc(3,1:states.Nmem-Ts/P)]; + o_f4_dc = [o_f4_dc states.f_dc(4,1:states.Nmem-Ts/P)]; + o_f3_int = [o_f3_int states.f_int(3,:)]; + o_f4_int = [o_f4_int states.f_int(4,:)]; + o_f3 = [o_f1 states.f(3)]; + o_f4 = [o_f1 states.f(4)]; + end + end + + %close all + + % One part-per-thousand allowed on important parameters + pass = 1; + + pass = vcompare(o_Sf, t_fft_est,'fft est',tname,.001,1) && pass; + pass = vcompare(o_fest, t_f_est,'f est',tname,.001,2) && pass; + pass = vcompare(o_rx_timing, t_rx_timing,'rx timing',tname,.02,3) && pass; + + if M==4 + pass = vcompare(o_f3_dc, t_f3_dc, 'f3 dc', tname,.005,4) && pass; + pass = vcompare(o_f4_dc, t_f4_dc, 'f4 dc', tname,.005,5) && pass; + pass = vcompare(o_f3_int, t_f3_int, 'f3 int', tname,.005,6) && pass; + pass = vcompare(o_f4_int, t_f4_int, 'f4 int', tname,.005,7) && pass; + end + + pass = vcompare(o_f1_dc, t_f1_dc, 'f1 dc', tname,.005,8) && pass; + pass = vcompare(o_f2_dc, t_f2_dc, 'f2 dc', tname,.005,9) && pass; + pass = vcompare(o_f2_int, t_f2_int, 'f2 int', tname,.005,10) && pass; + pass = vcompare(o_f1_int, t_f1_int, 'f1 int', tname,.005,11) && pass; + + % Much larger tolerances on unimportant statistics + pass = vcompare(o_ppm , t_ppm, 'ppm', tname,.02,12) && pass; + pass = vcompare(o_EbNodB, t_EbNodB,'EbNodB', tname,.02,13) && pass; + pass = vcompare(o_nin, t_nin, 'nin', tname,.0001,14) && pass; + pass = vcompare(o_norm_rx_timing, t_norm_rx_timing,'norm rx timing',tname,.02,15) && pass; + + assert(pass); + diffpass = sum(xor(obits,bits'))<4; + diffbits = sum(xor(obits,bits')); + + + if diffpass==0 + printf('\n***bitcompare test failed test %s diff %d\n\n',tname,sum(xor(obits,bits'))) + figure(15) + plot(xor(obits,bits')) + title(sprintf('Bitcompare failure test %s',tname)) + end + + pass = pass && diffpass; + + + test_stats.pass = pass; + test_stats.diff = sum(xor(obits,bits')); + test_stats.cbits = bits'; + test_stats.obits = obits; + +endfunction + +function [dmod,cmod,omod,pass] = fsk_mod_test(Fs,Rs,f1,fsp,bits,tname,M=2) + global mod_pass_fail_maxdiff; + %Run the C modulator + cmod = fsk_mod_c(Fs,Rs,f1,fsp,bits,M); + %Set up and run the octave modulator + states.M = M; + states = fsk_horus_init(Fs,Rs,M); + + states.ftx(1) = f1; + states.ftx(2) = f1+fsp; + + if states.M == 4 + states.ftx(3) = f1+fsp*2; + states.ftx(4) = f1+fsp*3; + end + + states.dA = [1 1 1 1]; + states.dF = 0; + omod = fsk_horus_mod(states,bits); + + dmod = cmod-omod; + pass = max(dmod)<(mod_pass_fail_maxdiff*length(dmod)); + if !pass + printf('Mod failed test %s!\n',tname); + end +endfunction + +% Random bit modulator test +% Pass random bits through the modulators and compare +function pass = test_mod_horuscfg_randbits + rand('state',1); + randn('state',1); + bits = rand(1,10000)>.5; + [dmod,cmod,omod,pass] = fsk_mod_test(8000,100,1200,1600,bits,"mod horuscfg randbits"); + + if(!pass) + figure(1) + plot(dmod) + title("Difference between octave and C mod impl"); + end + +endfunction + +% Random bit modulator test +% Pass random bits through the modulators and compare +function pass = test_mod_horuscfgm4_randbits + rand('state',1); + randn('state',1); + bits = rand(1,10000)>.5; + [dmod,cmod,omod,pass] = fsk_mod_test(8000,100,1200,1600,bits,"mod horuscfg randbits",4); + + if(!pass) + figure(1) + plot(dmod) + title("Difference between octave and C mod impl"); + end + +endfunction + +% A big ol' channel impairment tester +% Shamlessly taken from fsk_horus +% This throws some channel imparment or another at the C and octave modem so they +% may be compared. +function stats = tfsk_run_sim(test_frame_mode,EbNodB,timing_offset,fading,df,dA,M=2) + global print_verbose; + frames = 90; + %EbNodB = 10; + %timing_offset = 2.0; % see resample() for clock offset below + %fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + %df = 0; % tx tone freq drift in Hz/s + %dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',1); + randn('state',1); + + % ---------------------------------------------------------------------- + + % sm2000 config ------------------------ + %states = fsk_horus_init(96000, 1200); + %states.f1_tx = 4000; + %states.f2_tx = 5200; + + if test_frame_mode == 2 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100, M); + states.f1_tx = 1200; + states.f2_tx = 1600; + + end + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init(8000, 100, M); + states.f1_tx = 1200; + states.f2_tx = 1600; + states.tx_bits_file = "horus_tx_bits_rtty.txt"; % Octave file of bits we FSK modulate + + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init(8000, 100, M); + states.f1_tx = 1200; + states.f2_tx = 1600; + %%%states.tx_bits_file = "horus_tx_bits_binary.txt"; % Octave file of bits we FSK modulate + states.tx_bits_file = "horus_payload_rtty.txt"; + end + + % ---------------------------------------------------------------------- + + states.verbose = 0;%x1; + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + Fs = states.Fs; + states.df = df; + states.dA = [dA dA dA dA]; + states.M = M; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nsym)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nbit*(frames+1))); + end + if test_frame_mode == 3 + % ...10101... sequence + tx_bits = zeros(1, states.nsym*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + end + + if (test_frame_mode == 4) || (test_frame_mode == 5) + + % load up a horus msg from disk and modulate that + + test_frame = load(states.tx_bits_file); + ltf = length(test_frame); + ntest_frames = ceil((frames+1)*nsym/ltf); + tx_bits = []; + for i=1:ntest_frames + tx_bits = [tx_bits test_frame]; + end + end + + f1 = states.f1_tx; + fsp = states.f2_tx-f1; + states.dA = [dA dA dA dA]; + states.ftx(1) = f1; + states.ftx(2) = f1+fsp; + + if states.M == 4 + states.ftx(3) = f1+fsp*2; + states.ftx(4) = f1+fsp*3; + end + + tx = fsk_horus_mod(states, tx_bits); + + if timing_offset + tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + end + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + + test_name = sprintf("tfsk run sim EbNodB:%d frames:%d timing_offset:%d fading:%d df:%d",EbNodB,frames,timing_offset,fading,df); + tstats = fsk_demod_xt(Fs,Rs,states.f1_tx,fsp,rx,test_name,M); + + pass = tstats.pass; + obits = tstats.obits; + cbits = tstats.cbits; + + % Figure out BER of octave and C modems + bitcnt = length(tx_bits); + rx_bits = obits; + ber = 1; + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + bero = ber; + ber = 1; + rx_bits = cbits; + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + berc = ber; + stats.berc = berc; + stats.bero = bero; + stats.name = test_name; + % coherent BER theory calculation + + stats.thrcoh = .5*(M-1)*erfc(sqrt( (log2(M)/2) * EbNo )); + + % non-coherent BER theory calculation + % It was complicated, so I broke it up + + ms = M; + ns = (1:ms-1); + as = (-1).^(ns+1); + bs = (as./(ns+1)); + + cs = ((ms-1)./ns); + + ds = ns.*log2(ms); + es = ns+1; + fs = exp( -(ds./es)*EbNo ); + + thrncoh = ((ms/2)/(ms-1)) * sum(bs.*((ms-1)./ns).*exp( -(ds./es)*EbNo )); + + stats.thrncoh = thrncoh; + stats.pass = pass; +endfunction + + +function pass = ebno_battery_test(timing_offset,fading,df,dA,M) + %Range of EbNodB over which to test + ebnodbrange = (5:2:13); + ebnodbs = length(ebnodbrange); + + mode = 2; + %Replication of other parameters for parcellfun + modev = repmat(mode,1,ebnodbs); + timingv = repmat(timing_offset,1,ebnodbs); + fadingv = repmat(fading,1,ebnodbs); + dfv = repmat(df,1,ebnodbs); + dav = repmat(dA,1,ebnodbs); + mv = repmat(M,1,ebnodbs); + statv = pararrayfun(floor(1.25*nproc()),@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv); + + passv = zeros(1,length(statv)); + for ii=(1:length(statv)) + passv(ii)=statv(ii).pass; + if statv(ii).pass + printf("Test %s passed\n",statv(ii).name); + else + printf("Test %s failed\n",statv(ii).name); + end + end + + %All pass flags are '1' + pass = sum(passv)>=length(passv); + %and no tests died + pass = pass && length(passv)==ebnodbs; + passv; + assert(pass) +endfunction + +%Test with and without sample clock offset +function pass = test_timing_var(df,dA,M) + pass = ebno_battery_test(1,0,df,dA,M) + assert(pass) + pass = pass && ebno_battery_test(0,0,df,dA,M) + assert(pass) +endfunction + +%Test with and without 1 Hz/S freq drift +function pass = test_drift_var(M) + pass = test_timing_var(1,1,M) + assert(pass) + pass = pass && test_timing_var(0,1,M) + assert(pass) +endfunction + +function pass = test_fsk_battery() + pass = test_mod_horuscfg_randbits; + assert(pass) + pass = pass && test_mod_horuscfgm4_randbits; + assert(pass) + pass = pass && test_drift_var(4); + assert(pass) + pass = pass && test_drift_var(2); + assert(pass) + if pass + printf("***** All tests passed! *****\n"); + end +endfunction + +function plot_fsk_bers(M=2) + %Range of EbNodB over which to plot + ebnodbrange = (4:13); + + berc = ones(1,length(ebnodbrange)); + bero = ones(1,length(ebnodbrange)); + berinc = ones(1,length(ebnodbrange)); + beric = ones(1,length(ebnodbrange)); + ebnodbs = length(ebnodbrange) + mode = 2; + %Replication of other parameters for parcellfun + modev = repmat(mode,1,ebnodbs); + timingv = repmat(1,1,ebnodbs); + fadingv = repmat(0,1,ebnodbs); + dfv = repmat(1,1,ebnodbs); + dav = repmat(1,1,ebnodbs); + Mv = repmat(M,1,ebnodbs); + + + statv = pararrayfun(floor(nproc()),@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv); + + for ii = (1:length(statv)) + stat = statv(ii); + berc(ii)=stat.berc; + bero(ii)=stat.bero; + berinc(ii)=stat.thrncoh; + beric(ii) = stat.thrcoh; + end + clf; + figure(M) + + semilogy(ebnodbrange, berinc,sprintf('r;%dFSK non-coherent theory;',M)) + hold on; + semilogy(ebnodbrange, beric ,sprintf('g;%dFSK coherent theory;',M)) + semilogy(ebnodbrange, bero ,sprintf('b;Octave fsk horus %dFSK Demod;',M)) + semilogy(ebnodbrange, berc,sprintf('+;C fsk horus %dFSK Demod;',M)) + hold off; + grid("minor"); + axis([min(ebnodbrange) max(ebnodbrange) 1E-5 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + +endfunction + + +xpass = test_fsk_battery +%plot_fsk_bers(2) +plot_fsk_bers(4) + +if xpass + printf("***** All tests passed! *****\n"); +else + printf("***** Some test failed! Look back thorugh output to find failed test *****\n"); +end + diff --git a/codec2/branches/0.7/octave/tfsk_2400a.m b/codec2/branches/0.7/octave/tfsk_2400a.m new file mode 100644 index 00000000..a70044b0 --- /dev/null +++ b/codec2/branches/0.7/octave/tfsk_2400a.m @@ -0,0 +1,648 @@ +% tfsk.m +% Author: Brady O'Brien 8 January 2016 + + + +% Copyright 2016 David Rowe +% +% All rights reserved. +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Lesser General Public License version 2, as +% published by the Free Software Foundation. This program is +% distributed in the hope that it will be useful, but WITHOUT ANY +% WARRANTY; without even the implied warranty of MERCHANTABILITY or +% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +% License for more details. +% +% You should have received a copy of the GNU Lesser General Public License +% along with this program; if not, see . + + +% Octave script to check c port of fsk_horus against the fsk_horus.m +% +% [X] - Functions to wrap around fsk_mod and fsk_demod executables +% [X] - fsk_mod +% [X] - fsk_demod +% [X] - Functions to wrap around octave and c implementations, pass +% same dataset, compare outputs, and give clear go/no-go +% [X] - fsk_mod_test +% [X] - fsk_demod_test +% [X] - Port of run_sim and EbNodB curve test battery +% [X] - Extract and compare more parameters from demod +% [X] - Run some tests in parallel + +#{ + + FSK Modem automated test instructions: + + 1. Use cmake to build in debug mode to ensure unittest/tfsk is built: + + $ cd ~/codec2 + $ rm -Rf build_linux && mkdir build_linux + $ cd build_linux + $ cmake -DCMAKE_BUILD_TYPE=Debug .. + $ make + + 2 - Change tfsk_location below if required + 3 - Ensure Octave packages signal and parallel are installed + 4 - Start Octave and run tfsk_2400a.m. It will perform all tests automatically + +#} + + + +%tfsk executable path/file +global tfsk_location = '../build_linux/unittest/tfsk'; + +%Set to 1 for verbose printouts +global print_verbose = 0; + + +fsk_horus_as_a_lib = 1; % make sure calls to test functions at bottom are disabled +%fsk_horus_2fsk; +fsk_horus +pkg load signal; +pkg load parallel; +graphics_toolkit('gnuplot'); + + +global mod_pass_fail_maxdiff = 1e-3/5000; + +function mod = fsk_mod_c(Fs,Rs,f1,fsp,bits,M) + global tfsk_location; + %command to be run by system to launch the modulator + command = sprintf('%s MX %d %d %d %d %d fsk_mod_ut_bitvec fsk_mod_ut_modvec fsk_mod_ut_log.txt',tfsk_location,M,f1,fsp,Fs,Rs); + %save input bits into a file + bitvecfile = fopen('fsk_mod_ut_bitvec','wb+'); + fwrite(bitvecfile,bits,'uint8'); + fclose(bitvecfile); + + %run the modulator + system(command); + + modvecfile = fopen('fsk_mod_ut_modvec','rb'); + mod = fread(modvecfile,'single'); + fclose(modvecfile); + +endfunction + + +%Compare 2 vectors, fail if they are not close enough +function pass = vcompare(vc,voct,vname,tname,tol,pnum) + global print_verbose; + %Get delta of vectors + dvec = abs(abs(vc)-abs(voct)); + + %Normalize difference + dvec = dvec ./ abs(max(abs(voct))+1e-8); + + maxdvec = abs(max(dvec)); + pass = maxdvec=states.nin + ninold = states.nin; + states = est_freq(states, modin(1:states.nin), states.M); + [bitbuf,states] = fsk_horus_demod(states, modin(1:states.nin)); + modin=modin(ninold+1:length(modin)); + obits = [obits bitbuf]; + + %Save other parameters + o_f1_dc = [o_f1_dc states.f_dc(1,1:states.Nmem-Ts/P)]; + o_f2_dc = [o_f2_dc states.f_dc(2,1:states.Nmem-Ts/P)]; + o_f1_int = [o_f1_int states.f_int(1,:)]; + o_f2_int = [o_f2_int states.f_int(2,:)]; + o_EbNodB = [o_EbNodB states.EbNodB]; + o_ppm = [o_ppm states.ppm]; + o_rx_timing = [o_rx_timing states.rx_timing]; + o_norm_rx_timing = [o_norm_rx_timing states.norm_rx_timing]; + o_Sf = [o_Sf states.Sf']; + o_f1 = [o_f1 states.f(1)]; + o_f2 = [o_f1 states.f(2)]; + o_fest = [o_fest states.f]; + o_nin = [o_nin states.nin]; + if M==4 + o_f3_dc = [o_f3_dc states.f_dc(3,1:states.Nmem-Ts/P)]; + o_f4_dc = [o_f4_dc states.f_dc(4,1:states.Nmem-Ts/P)]; + o_f3_int = [o_f3_int states.f_int(3,:)]; + o_f4_int = [o_f4_int states.f_int(4,:)]; + o_f3 = [o_f1 states.f(3)]; + o_f4 = [o_f1 states.f(4)]; + end + end + + %close all + + pass = 1; + + pass = vcompare(o_Sf, t_fft_est(1:length(o_Sf)),'fft est',tname,1,1) && pass; + pass = vcompare(o_fest, t_f_est,'f est',tname,1,2) && pass; + pass = vcompare(o_rx_timing, t_rx_timing,'rx timing',tname,1,3) && pass; + + if M==4 + pass = vcompare(o_f3_dc, t_f3_dc, 'f3 dc', tname,1,4) && pass; + pass = vcompare(o_f4_dc, t_f4_dc, 'f4 dc', tname,1,5) && pass; + pass = vcompare(o_f3_int, t_f3_int, 'f3 int', tname,1,6) && pass; + pass = vcompare(o_f4_int, t_f4_int, 'f4 int', tname,1,7) && pass; + end + + pass = vcompare(o_f1_dc, t_f1_dc, 'f1 dc', tname,1,8) && pass; + pass = vcompare(o_f2_dc, t_f2_dc, 'f2 dc', tname,1,9) && pass; + pass = vcompare(o_f2_int, t_f2_int, 'f2 int', tname,1,10) && pass; + pass = vcompare(o_f1_int, t_f1_int, 'f1 int', tname,1,11) && pass; + + pass = vcompare(o_ppm , t_ppm, 'ppm', tname,1,12) && pass; + pass = vcompare(o_EbNodB, t_EbNodB,'EbNodB', tname,1,13) && pass; + pass = vcompare(o_nin, t_nin, 'nin', tname,1,14) && pass; + pass = vcompare(o_norm_rx_timing, t_norm_rx_timing,'norm rx timing',tname,1,15) && pass; + + + diffpass = sum(xor(obits,bits'))<5; + diffbits = sum(xor(obits,bits')); + + if print_verbose == 1 + printf('%d bit diff in test %s\n',diffbits,tname); + end + if diffpass==0 + printf('\n***bitcompare test failed test %s diff %d\n\n',tname,sum(xor(obits,bits'))) + figure(15) + plot(xor(obits,bits')) + title(sprintf('Bitcompare failure test %s',tname)) + end + + pass = pass && diffpass; + + assert(pass); + + test_stats.pass = pass; + test_stats.diff = sum(xor(obits,bits')); + test_stats.cbits = bits'; + test_stats.obits = obits; + +endfunction + +function [dmod,cmod,omod,pass] = fsk_mod_test(Fs,Rs,f1,fsp,bits,tname,M=2) + global mod_pass_fail_maxdiff; + %Run the C modulator + cmod = fsk_mod_c(Fs,Rs,f1,fsp,bits,M); + %Set up and run the octave modulator + states.M = M; + states = fsk_horus_init_hbr(Fs,10,Rs,M); + + states.ftx(1) = f1; + states.ftx(2) = f1+fsp; + + if states.M == 4 + states.ftx(3) = f1+fsp*2; + states.ftx(4) = f1+fsp*3; + end + + states.dA = [1 1 1 1]; + states.dF = 0; + omod = fsk_horus_mod(states,bits); + + dmod = cmod-omod; + pass = max(dmod)<(mod_pass_fail_maxdiff*length(dmod)); + if !pass + printf('Mod failed test %s!\n',tname); + end +endfunction + +% Random bit modulator test +% Pass random bits through the modulators and compare +function pass = test_mod_2400a_randbits + rand('state',1); + randn('state',1); + bits = rand(1,96000)>.5; + [dmod,cmod,omod,pass] = fsk_mod_test(48000,1200,1200,1200,bits,"mod 2400a randbits",4); + + if(!pass) + figure(1) + plot(dmod) + title("Difference between octave and C mod impl"); + end + +endfunction + + +% A big ol' channel impairment tester +% Shamlessly taken from fsk_horus +% This throws some channel imparment or another at the C and octave modem so they +% may be compared. +function stats = tfsk_run_sim(test_frame_mode,EbNodB,timing_offset,fading,df,dA,M=2) + global print_verbose; + frames = 190; + %EbNodB = 10; + %timing_offset = 2.0; % see resample() for clock offset below + %fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + %df = 0; % tx tone freq drift in Hz/s + %dA = 1; % amplitude imbalance of tones (note this affects Eb so not a gd idea) + + more off + rand('state',10); + randn('state',10); + + % ---------------------------------------------------------------------- + + % sm2000 config ------------------------ + %states = fsk_horus_init(96000, 1200); + %states.f1_tx = 4000; + %states.f2_tx = 5200; + + if test_frame_mode == 2 + % 2400A config + states = fsk_horus_init_hbr(48000,10, 1200, M); + states.f1_tx = 1200; + states.f2_tx = 2400; + states.f3_tx = 3600; + states.f4_tx = 4800; + states.ftx(1) = 1200; + states.ftx(2) = 2400; + states.ftx(3) = 3600; + states.ftx(4) = 4800; + + end + + if test_frame_mode == 4 + % horus rtty config --------------------- + states = fsk_horus_init_hbr(48000,10, 1200, M); + states.f1_tx = 1200; + states.f2_tx = 2400; + states.f3_tx = 3600; + states.f4_tx = 4800; + states.ftx(1) = 1200; + states.ftx(2) = 2400; + states.ftx(3) = 3600; + states.ftx(4) = 4800; + + states.tx_bits_file = "horus_tx_bits_rtty.txt"; % Octave file of bits we FSK modulate + + end + + if test_frame_mode == 5 + % horus binary config --------------------- + states = fsk_horus_init_hbr(48000,10, 1200, M); + states.f1_tx = 1200; + states.f2_tx = 2400; + states.f3_tx = 3600; + states.f4_tx = 4800; + states.ftx(1) = 1200; + states.ftx(2) = 2400; + states.ftx(3) = 3600; + states.ftx(4) = 4800; + %%%states.tx_bits_file = "horus_tx_bits_binary.txt"; % Octave file of bits we FSK modulate + states.tx_bits_file = "horus_payload_rtty.txt"; + end + + % ---------------------------------------------------------------------- + + states.verbose = 0;%x1; + N = states.N; + P = states.P; + Rs = states.Rs; + nsym = states.nsym; + Fs = states.Fs; + states.df = df; + states.dA = [dA dA dA dA]; + states.M = M; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo*states.bitspersymbol); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nsym)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nbit*(frames+1))); + end + if test_frame_mode == 3 + % ...10101... sequence + tx_bits = zeros(1, states.nsym*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + end + + if (test_frame_mode == 4) || (test_frame_mode == 5) + + % load up a horus msg from disk and modulate that + + test_frame = load(states.tx_bits_file); + ltf = length(test_frame); + ntest_frames = ceil((frames+1)*nsym/ltf); + tx_bits = []; + for i=1:ntest_frames + tx_bits = [tx_bits test_frame]; + end + end + + + + f1 = states.f1_tx; + fsp = states.f2_tx-f1; + states.dA = [dA dA dA dA]; + states.ftx(1) = f1; + states.ftx(2) = f1+fsp; + + if states.M == 4 + states.ftx(3) = f1+fsp*2; + states.ftx(4) = f1+fsp*3; + end + + tx = fsk_horus_mod(states, tx_bits); + + if timing_offset + tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + end + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + + test_name = sprintf("tfsk EbNodB:%d frames:%d timing_offset:%d fading:%d df:%d",EbNodB,frames,timing_offset,fading,df); + tstats = fsk_demod_xt(Fs,Rs,states.f1_tx,fsp,rx,test_name,M); + + pass = tstats.pass; + obits = tstats.obits; + cbits = tstats.cbits; + stats.name = test_name; + + if tstats.pass + printf("Test %s passed\n",test_name); + else + printf("Test %s failed\n",test_name); + end + + % Figure out BER of octave and C modems + bitcnt = length(tx_bits); + rx_bits = obits; + ber = 1; + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + bero = ber; + ber = 1; + rx_bits = cbits; + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),tx_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + berc = ber; + stats.berc = berc; + stats.bero = bero; + % coherent BER theory calculation + + if print_verbose == 1 + printf("C BER: %f Oct BER: %f Test %s\n",berc,bero,test_name); + end + + stats.thrcoh = .5*(M-1)*erfc(sqrt( (log2(M)/2) * EbNo )); + + % non-coherent BER theory calculation + % It was complicated, so I broke it up + + ms = M; + ns = (1:ms-1); + as = (-1).^(ns+1); + bs = (as./(ns+1)); + + cs = ((ms-1)./ns); + + ds = ns.*log2(ms); + es = ns+1; + fs = exp( -(ds./es)*EbNo ); + + thrncoh = ((ms/2)/(ms-1)) * sum(bs.*((ms-1)./ns).*exp( -(ds./es)*EbNo )); + + stats.thrncoh = thrncoh; + stats.pass = pass; +endfunction + + +function pass = ebno_battery_test(timing_offset,fading,df,dA,M) + %Range of EbNodB over which to test + ebnodbrange = fliplr(5:2:13); + ebnodbs = length(ebnodbrange); + + mode = 2; + %Replication of other parameters for parcellfun + modev = repmat(mode,1,ebnodbs); + timingv = repmat(timing_offset,1,ebnodbs); + fadingv = repmat(fading,1,ebnodbs); + dfv = repmat(df,1,ebnodbs); + dav = repmat(dA,1,ebnodbs); + mv = repmat(M,1,ebnodbs); + statv = pararrayfun(floor(1.25*nproc()),@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,mv); + + passv = zeros(1,length(statv)); + for ii=(1:length(statv)) + passv(ii)=statv(ii).pass; + if statv(ii).pass + printf("Test %s passed\n",statv(ii).name); + else + printf("Test %s failed\n",statv(ii).name); + end + + end + + %All pass flags are '1' + pass = sum(passv)>=length(passv); + %and no tests died + pass = pass && length(passv)==ebnodbs; + passv; + assert(pass) +endfunction + +%Test with and without sample clock offset +function pass = test_timing_var(df,dA,M) + pass = ebno_battery_test(1,0,df,dA,M) + assert(pass) + pass = pass && ebno_battery_test(0,0,df,dA,M) + assert(pass) +endfunction + +%Test with and without 1 Hz/S freq drift +function pass = test_drift_var(M) + pass = test_timing_var(1,1,M) + assert(pass) + pass = pass && test_timing_var(0,1,M) + assert(pass) +endfunction + +function pass = test_fsk_battery() + pass = 1; + pass = pass && test_mod_2400a_randbits; + assert(pass) + pass = pass && test_drift_var(4); + assert(pass) + if pass + printf("***** All tests passed! *****\n"); + end +endfunction + +function plot_fsk_bers(M=2) + %Range of EbNodB over which to plot + ebnodbrange = (4:13); + + berc = ones(1,length(ebnodbrange)); + bero = ones(1,length(ebnodbrange)); + berinc = ones(1,length(ebnodbrange)); + beric = ones(1,length(ebnodbrange)); + ebnodbs = length(ebnodbrange) + mode = 2; + %Replication of other parameters for parcellfun + modev = repmat(mode,1,ebnodbs); + timingv = repmat(1,1,ebnodbs); + fadingv = repmat(0,1,ebnodbs); + dfv = repmat(1,1,ebnodbs); + dav = repmat(1,1,ebnodbs); + Mv = repmat(M,1,ebnodbs); + + + statv = pararrayfun(floor(nproc()),@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv); + %statv = arrayfun(@tfsk_run_sim,modev,ebnodbrange,timingv,fadingv,dfv,dav,Mv); + + for ii = (1:length(statv)) + stat = statv(ii); + berc(ii)=stat.berc; + bero(ii)=stat.bero; + berinc(ii)=stat.thrncoh; + beric(ii) = stat.thrcoh; + end + clf; + figure(M) + + semilogy(ebnodbrange, berinc,sprintf('r;%dFSK non-coherent theory;',M)) + hold on; + semilogy(ebnodbrange, beric ,sprintf('g;%dFSK coherent theory;',M)) + semilogy(ebnodbrange, bero ,sprintf('b;Octave fsk horus %dFSK Demod;',M)) + semilogy(ebnodbrange, berc,sprintf('+;C fsk horus %dFSK Demod;',M)) + hold off; + grid("minor"); + axis([min(ebnodbrange) max(ebnodbrange) 1E-5 1]) + legend("boxoff"); + xlabel("Eb/No (dB)"); + ylabel("Bit Error Rate (BER)") + +endfunction + + +xpass = test_fsk_battery +%plot_fsk_bers(2) +plot_fsk_bers(4) + +if xpass + printf("***** All tests passed! *****\n"); +else + printf("***** Some test failed! Look back thorugh output to find failed test *****\n"); +end diff --git a/codec2/branches/0.7/octave/tget_spec.m b/codec2/branches/0.7/octave/tget_spec.m new file mode 100644 index 00000000..e46c1ea0 --- /dev/null +++ b/codec2/branches/0.7/octave/tget_spec.m @@ -0,0 +1,49 @@ +% tget-spec.m +% +% Used in conjunction with src/fdmdv_demod to test the +% fdmdv_get_rx_spectrum() function. +% +% codec2-dev/src$ ./fdmdv_demod fdmdv_mod.raw tmp.c2 dump.txt +% octave:3> tget_spec("../src/dump.txt") +% +% Copyright David Rowe 2012 +% This program is distributed under the terms of the GNU General Public License +% Version 2 +% + +function tfft_log(dumpfilename) + + load(dumpfilename); + + [rows cols] = size(rx_spec_log_c); + Fs = 8000; low_freq = 0; high_freq = 2500; + res = (Fs/2)/cols; + st_bin = low_freq/res + 1; + en_bin = high_freq/res; + xaxis = (st_bin:en_bin)*res; + + f_start = 2; f_end = 100; + beta = 0.1; + + av = zeros(f_end, en_bin-st_bin+1); + for r=f_start:f_end + x = (1-beta)*av(r-1,:) + beta*rx_spec_log_c(r,st_bin:en_bin); + av(r,:) = x; + end + + % spectrogram (waterfall) + + figure(1) + clf; + imagesc(av,[-40 0]); + + % animated spectrum display + + figure(2) + clf; + for r=f_start:f_end + plot(xaxis, av(r,:)) + axis([ low_freq high_freq -40 0]) + sleep(0.1) + end +endfunction diff --git a/codec2/branches/0.7/octave/tlinreg.m b/codec2/branches/0.7/octave/tlinreg.m new file mode 100644 index 00000000..1cde350d --- /dev/null +++ b/codec2/branches/0.7/octave/tlinreg.m @@ -0,0 +1,14 @@ +% tlinreg +% David Rowe April 2015 +% +% Unit test for linear regression + +x = [1 2 7 8]; +y = [ -0.70702 + 0.70708i 0.77314 - 0.63442i -0.98083 + 0.19511i 0.99508 - 0.09799i] .* [1 -1 1 -1]; +[m b] = linreg(x,y,4); + +x = [1 2 3 4 5 6 7 8]; +yFit = m * x + b; +figure(1) +plot(yFit,'r*') +axis([-1.5 1.5 -1.5 1.5]) diff --git a/codec2/branches/0.7/octave/tnewamp1.m b/codec2/branches/0.7/octave/tnewamp1.m new file mode 100644 index 00000000..be6788ed --- /dev/null +++ b/codec2/branches/0.7/octave/tnewamp1.m @@ -0,0 +1,237 @@ +% tnewamp1.m +% +% Copyright David Rowe 2017 +% This program is distributed under the terms of the GNU General Public License +% Version 2 + +#{ + + Octave script to compare Octave and C versions of newamp1 processing, in order to test C port. + + c2sim -> dump files -> $ ../build_linux/unittest/tnewamp1 -> octave:1> tnewamp1 + Usage: + + 1/ build codec2 with -DDUMP - see codec2-dev/README + + 2/ Generate dump files using c2sim (just need to do this once) + $ cd codec2-dev/build_linux/src + $ ./c2sim ../../raw/hts1a.raw --phase0 --postfilter --dump hts1a --lpc 10 --dump_pitch_e hts1a_pitche.txt + + 3/ Run C version which generates a file of Octave test vectors as ouput: + + $ cd codec2-dev/build_linux/unittest + $ ./tnewamp1 ../../raw/hts1a + + 4/ Run Octave script to generate Octave test vectors and compare with C. + + octave:1> tnewamp1("../build_linux/src/hts1a") + + 5/ Optionally listen to output + + ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --phase0 --postfilter \ + --amread hts1a_am.out --hmread hts1a_hm.out \ + --Woread hts1a_Wo.out --hand_voicing hts1a_v.txt -o - \ + | play -q -t raw -r 8000 -s -2 - +#} + + +% In general, this function processes a bunch of amplitudes, we then +% use c2sim to hear the results. Bunch of different experiments below + +function tnewamp1(input_prefix) + newamp; + autotest; + more off; + + max_amp = 80; + postfilter = 0; % optional postfiler that runs on Am, not used atm + synth_phase = 1; + + if nargin == 1 + output_prefix = input_prefix; + end + model_name = strcat(input_prefix,"_model.txt"); + model = load(model_name); + [frames nc] = size(model); + + voicing_name = strcat(input_prefix,"_pitche.txt"); + voicing = zeros(1,frames); + + if exist(voicing_name, "file") == 2 + pitche = load(voicing_name); + voicing = pitche(:, 3); + end + + % Load in C vectors and compare ----------------------------------------- + + load("../build_linux/unittest/tnewamp1_out.txt"); + + K = 20; + [frames tmp] = size(rate_K_surface_c); + [rate_K_surface sample_freqs_kHz] = resample_const_rate_f_mel(model(1:frames,:), K); + + melvq; + load train_120_vq; m=5; + + for f=1:frames + mean_f(f) = mean(rate_K_surface(f,:)); + rate_K_surface_no_mean(f,:) = rate_K_surface(f,:) - mean_f(f); + end + + [res rate_K_surface_no_mean_ ind] = mbest(train_120_vq, rate_K_surface_no_mean, m); + + for f=1:frames + rate_K_surface_no_mean_(f,:) = post_filter(rate_K_surface_no_mean_(f,:), sample_freqs_kHz, 1.5); + end + + rate_K_surface_ = zeros(frames, K); + interpolated_surface_ = zeros(frames, K); + energy_q = create_energy_q; + M = 4; + for f=1:frames + [mean_f_ indx] = quantise(energy_q, mean_f(f)); + indexes(f,3) = indx - 1; + rate_K_surface_(f,:) = rate_K_surface_no_mean_(f,:) + mean_f_; + end + + % simulated decoder + % break into segments of M frames. We have 2 samples spaced M apart + % and interpolate the rest. + + Nfft_phase = 128; % note this needs to be 512 (FFT_ENC in codec2 if using --awread) + % with --hmread 128 is preferred as less memory/CPU + model_ = zeros(frames, max_amp+2); + voicing_ = zeros(1,frames); + Aw = zeros(frames, Nfft_phase); + H = zeros(frames, max_amp); + model_(1,1) = Wo_left = 2*pi/100; + voicing_left = 0; + left_vec = zeros(1,K); + + % decoder runs on every M-th frame, 25Hz frame rate, offset at + % start is to minimise processing delay (thanks Jeroen!) + + for f=M:M:frames + + if voicing(f) + index = encode_log_Wo(model(f,1), 6); + if index == 0 + index = 1; + end + model_(f,1) = decode_log_Wo(index, 6); + else + model_(f,1) = 2*pi/100; + end + + Wo_right = model_(f,1); + voicing_right = voicing(f); + [Wo_ avoicing_] = interp_Wo_v(Wo_left, Wo_right, voicing_left, voicing_right); + + if f > M + model_(f-M:f-1,1) = Wo_; + voicing_(f-M:f-1) = avoicing_; + model_(f-M:f-1,2) = floor(pi ./ model_(f-M:f-1,1)); % calculate L for each interpolated Wo + end + + right_vec = rate_K_surface_(f,:); + + if f > M + sample_points = [f-M f]; + resample_points = f-M:f-1; + for k=1:K + interpolated_surface_(resample_points,k) = interp_linear(sample_points, [left_vec(k) right_vec(k)], resample_points); + end + + for k=f-M:f-1 + model_(k,:) = resample_rate_L(model_(k,:), interpolated_surface_(k,:), sample_freqs_kHz); + Aw(k,:) = determine_phase(model_, k, Nfft_phase); + for m=1:model_(k,2) + b = round(m*model_(k,1)*Nfft_phase/(2*pi)); % map harmonic centre to DFT bin + H(k,m) = exp(j*Aw(k, b+1)); + end + end + end + + % update for next time + + Wo_left = Wo_right; + voicing_left = voicing_right; + left_vec = right_vec; + + end + + figure(1); clf; + mesh(angle(H)); + figure(2); clf; + mesh(angle(H_c)); + figure(3); clf; + mesh(abs(H - H_c)); + + check(rate_K_surface, rate_K_surface_c, 'rate_K_surface', 0.01); + check(mean_f, mean_c, 'mean', 0.01); + check(rate_K_surface_, rate_K_surface__c, 'rate_K_surface_', 0.01); + check(interpolated_surface_, interpolated_surface__c, 'interpolated_surface_', 0.01); + check(model_(:,1), model__c(:,1), 'interpolated Wo_', 0.001); + check(voicing_, voicing__c, 'interpolated voicing'); + check(model_(:,3:max_amp+2), model__c(:,3:max_amp+2), 'rate L Am surface ', 0.1); + check(H, H_c, 'phase surface'); + + % Save to disk to check synthesis is OK with c2sim + + output_prefix = input_prefix; + Am_out_name = sprintf("%s_am.out", output_prefix); + fam = fopen(Am_out_name,"wb"); + + Wo_out_name = sprintf("%s_Wo.out", output_prefix); + fWo = fopen(Wo_out_name,"wb"); + + Aw_out_name = sprintf("%s_aw.out", output_prefix); + faw = fopen(Aw_out_name,"wb"); + + Hm_out_name = sprintf("%s_hm.out", output_prefix); + fhm = fopen(Hm_out_name,"wb"); + + printf("Generating files for c2sim: "); + for f=1:frames + printf(".", f); + Wo = model_(f,1); + L = min([model_(f,2) max_amp-1]); + Am = model_(f,3:(L+2)); + + Am_ = zeros(1,max_amp); + Am_(2:L) = Am(1:L-1); + + fwrite(fam, Am_, "float32"); + fwrite(fWo, Wo, "float32"); + + % Note we send opposite phase as c2sim expects phase of LPC + % analysis filter, just a convention based on historical + % development of Codec 2 + + Aw1 = zeros(1, Nfft_phase*2); + Aw1(1:2:Nfft_phase*2) = cos(Aw(f,:)); + Aw1(2:2:Nfft_phase*2) = -sin(Aw(f,:)); + fwrite(faw, Aw1, "float32"); + + Hm = zeros(1, 2*max_amp); + for m=1:L + Hm(2*m+1) = real(H(f,m)); + Hm(2*m+2) = imag(H(f,m)); + end + fwrite(fhm, Hm, "float32"); + end + + fclose(fam); fclose(fWo); fclose(faw); fclose(fhm); + + v_out_name = sprintf("%s_v.txt", output_prefix); + fv = fopen(v_out_name,"wt"); + for f=1:length(voicing__c) + fprintf(fv,"%d\n", voicing__c(f)); + end + fclose(fv); + + printf("\n") + +endfunction + + diff --git a/codec2/branches/0.7/octave/tofdm.m b/codec2/branches/0.7/octave/tofdm.m new file mode 100644 index 00000000..73b99fea --- /dev/null +++ b/codec2/branches/0.7/octave/tofdm.m @@ -0,0 +1,159 @@ +% tofdm.m +% David Rowe and Steve Sampson June 2017 +% +% Octave script for comparing Octave and C versions of OFDZM modem + +% ------------------------------------------------------------------ + +Nframes = 30; +sample_clock_offset_ppm = 100; +foff_hz = 0.5; + +more off; format; +ofdm_lib; +autotest; + +% --------------------------------------------------------------------- +% Run Octave version +% --------------------------------------------------------------------- + +Ts = 0.018; Tcp = 0.002; Rs = 1/Ts; bps = 2; Nc = 16; Ns = 8; +states = ofdm_init(bps, Rs, Tcp, Ns, Nc); +ofdm_load_const; + +rand('seed',1); +tx_bits = round(rand(1,Nbitsperframe)); + +% Run tx loop + +tx_bits_log = []; tx_log = []; +for f=1:Nframes + tx_bits_log = [tx_bits_log tx_bits]; + tx_log = [tx_log ofdm_mod(states, tx_bits)]; +end + +% Channel simulation ---------------------------------------------- + +rx_log = sample_clock_offset(tx_log, sample_clock_offset_ppm); +rx_log = freq_shift(rx_log, foff_hz, Fs); + +% Rx --------------------------------------------------------------- + +% Init rx with ideal timing so we can test with timing estimation disabled + +Nsam = length(rx_log); +prx = 1; +nin = Nsamperframe+2*(M+Ncp); +states.rxbuf(Nrxbuf-nin+1:Nrxbuf) = rx_log(prx:nin); +prx += nin; + +rxbuf_log = []; rxbuf_in_log = []; rx_sym_log = []; foff_hz_log = []; +timing_est_log = []; sample_point_log = []; +phase_est_pilot_log = []; rx_amp_log = []; +rx_np_log = []; rx_bits_log = []; + +states.timing_en = 1; +states.foff_est_en = 1; +states.phase_est_en = 1; + +if states.timing_en == 0 + % manually set ideal timing instant + states.sample_point = Ncp; +end + +for f=1:Nframes + + % insert samples at end of buffer, set to zero if no samples + % available to disable phase estimation on future pilots on last + % frame of simulation + + nin = states.nin; + lnew = min(Nsam-prx+1,nin); + rxbuf_in = zeros(1,nin); + %printf("nin: %d prx: %d lnew: %d\n", nin, prx, lnew); + if lnew + rxbuf_in(1:lnew) = rx_log(prx:prx+lnew-1); + end + prx += lnew; + + [rx_bits states aphase_est_pilot_log arx_np arx_amp] = ofdm_demod(states, rxbuf_in); + + % log some states for comparison to C + + rxbuf_in_log = [rxbuf_in_log rxbuf_in]; + rxbuf_log = [rxbuf_log states.rxbuf]; + rx_sym_log = [rx_sym_log; states.rx_sym]; + phase_est_pilot_log = [phase_est_pilot_log; aphase_est_pilot_log]; + rx_amp_log = [rx_amp_log arx_amp]; + foff_hz_log = [foff_hz_log; states.foff_est_hz]; + timing_est_log = [timing_est_log; states.timing_est]; + sample_point_log = [sample_point_log; states.sample_point]; + rx_np_log = [rx_np_log arx_np]; + rx_bits_log = [rx_bits_log rx_bits]; + +end + +% --------------------------------------------------------------------- +% Run C version and plot Octave and C states and differences +% --------------------------------------------------------------------- + +% Override default path by setting path_to_tofdm = "/your/path/to/tofdm" + +if exist("path_to_tofdm", "var") == 0 + path_to_tofdm = "../build_linux/unittest/tofdm"; +end +system(path_to_tofdm); + +load tofdm_out.txt; + +fg = 1; +figure(fg++); clf; plot(rx_np_log,'+'); title('Octave Scatter Diagram'); axis([-1.5 1.5 -1.5 1.5]); +figure(fg++); clf; plot(rx_np_log_c,'+'); title('C Scatter Diagram'); axis([-1.5 1.5 -1.5 1.5]); + +stem_sig_and_error(fg++, 111, tx_bits_log_c, tx_bits_log - tx_bits_log_c, 'tx bits', [1 length(tx_bits_log) -1.5 1.5]) + +stem_sig_and_error(fg, 211, real(tx_log_c), real(tx_log - tx_log_c), 'tx re', [1 length(tx_log_c) -0.1 0.1]) +stem_sig_and_error(fg++, 212, imag(tx_log_c), imag(tx_log - tx_log_c), 'tx im', [1 length(tx_log_c) -0.1 0.1]) + +stem_sig_and_error(fg, 211, real(rx_log_c), real(rx_log - rx_log_c), 'rx re', [1 length(rx_log_c) -0.1 0.1]) +stem_sig_and_error(fg++, 212, imag(rx_log_c), imag(rx_log - rx_log_c), 'rx im', [1 length(rx_log_c) -0.1 0.1]) + +stem_sig_and_error(fg, 211, real(rxbuf_in_log_c), real(rxbuf_in_log - rxbuf_in_log_c), 'rxbuf in re', [1 length(rxbuf_in_log_c) -0.1 0.1]) +stem_sig_and_error(fg++, 212, imag(rxbuf_in_log_c), imag(rxbuf_in_log - rxbuf_in_log_c), 'rxbuf in im', [1 length(rxbuf_in_log_c) -0.1 0.1]) + +stem_sig_and_error(fg, 211, real(rxbuf_log_c), real(rxbuf_log - rxbuf_log_c), 'rxbuf re', [1 length(rxbuf_log_c) -0.1 0.1]) +stem_sig_and_error(fg++, 212, imag(rxbuf_log_c), imag(rxbuf_log - rxbuf_log_c), 'rxbuf im', [1 length(rxbuf_log_c) -0.1 0.1]) + +stem_sig_and_error(fg, 211, real(rx_sym_log_c), real(rx_sym_log - rx_sym_log_c), 'rx sym re', [1 length(rx_sym_log_c) -1.5 1.5]) +stem_sig_and_error(fg++, 212, imag(rx_sym_log_c), imag(rx_sym_log - rx_sym_log_c), 'rx sym im', [1 length(rx_sym_log_c) -1.5 1.5]) + +% for angles pi and -pi are the same + +d = phase_est_pilot_log - phase_est_pilot_log_c; d = angle(exp(j*d)); + +stem_sig_and_error(fg, 211, phase_est_pilot_log_c, d, 'phase est pilot', [1 length(phase_est_pilot_log_c) -1.5 1.5]) +stem_sig_and_error(fg++, 212, rx_amp_log_c, rx_amp_log - rx_amp_log_c, 'rx amp', [1 length(rx_amp_log_c) -1.5 1.5]) + +stem_sig_and_error(fg++, 111, foff_hz_log_c, (foff_hz_log - foff_hz_log_c), 'foff hz', [1 length(foff_hz_log_c) -1.5 1.5]) + +stem_sig_and_error(fg, 211, timing_est_log_c, (timing_est_log - timing_est_log_c), 'timing est', [1 length(timing_est_log_c) -1.5 1.5]) +stem_sig_and_error(fg++, 212, sample_point_log_c, (sample_point_log - sample_point_log_c), 'sample point', [1 length(sample_point_log_c) -1.5 1.5]) + +stem_sig_and_error(fg++, 111, rx_bits_log_c, rx_bits_log - rx_bits_log_c, 'rx bits', [1 length(rx_bits_log) -1.5 1.5]) + +% Run through checklist ----------------------------- + +check_no_abs(W, W_c, 'W'); +check(tx_bits_log, tx_bits_log_c, 'tx_bits'); +check(tx_log, tx_log_c, 'tx'); +check(rx_log, rx_log_c, 'rx'); +check(rxbuf_in_log, rxbuf_in_log_c, 'rxbuf in'); +check(rxbuf_log, rxbuf_log_c, 'rxbuf'); +check(rx_sym_log, rx_sym_log_c, 'rx_sym'); +check(phase_est_pilot_log, phase_est_pilot_log_c, 'phase_est_pilot', tol=1E-3, its_an_angle=1); +check(rx_amp_log, rx_amp_log_c, 'rx_amp'); +check(timing_est_log, timing_est_log_c, 'timing_est'); +check(sample_point_log, sample_point_log_c, 'sample_point'); +check(foff_hz_log, foff_hz_log_c, 'foff_est_hz'); +check(rx_bits_log, rx_bits_log_c, 'rx_bits'); + diff --git a/codec2/branches/0.7/octave/tpapr.m b/codec2/branches/0.7/octave/tpapr.m new file mode 100644 index 00000000..194d9a7d --- /dev/null +++ b/codec2/branches/0.7/octave/tpapr.m @@ -0,0 +1,35 @@ +% tpapr.m +% David Rowe +% 18 May 2015 + +graphics_toolkit ("gnuplot"); +rand('state',1); + +Fs = 8000; +Rs = 50; +Nc = 8; +Fc = 1500; +Fsep = ((1:Nc).^1.2)*75; +%Fsep = (1:Nc)*75 + 5 - 20*rand(1,Nc) +n = 80000; +t = 1:n; +tx = zeros(1,n); +phi = ones(1,Nc); + +figure(1) +clf + +for m=1:Nc + s = cos(phi(m)+t*2*pi*(Rs/2 + Fc + Fsep(m))/Fs); + tx += s; + subplot(Nc,1,m); + plot(s) +end + +figure(2) +plot(tx) + +tx = tx(length(tx)*0.5:length(tx)); +papr = max(tx.*conj(tx)) / mean(tx.*conj(tx)); +papr_dB = 10*log10(papr); +printf("PAPR: %4.2f dB\n", papr_dB); diff --git a/codec2/branches/0.7/octave/tqpsk.m b/codec2/branches/0.7/octave/tqpsk.m new file mode 100644 index 00000000..f6557c91 --- /dev/null +++ b/codec2/branches/0.7/octave/tqpsk.m @@ -0,0 +1,230 @@ +% tqpsk.m +% +% David Rowe Sep 2015 +% +% QPSK modem Octave test scripts + +% TODO: +% correct freq offset +% output tx frame to a file of bits for 3rd party modulator +% improve phase est impl loss using longer window +% separate into mod and demod functions +% generate filter coeffs, save to C header file +% fine timing estimator and meas IL +% coarse timing (frame sync) + +% make sure we get same random numbers every time + +more off; +qpsk; +ldpc; + + +function [aqpsk code_param] = init_modem_ldpc + + % Init modem ------------------------------------------------------------------------------ + + aqpsk.Rbdata = 2400; % bit rate (Hz) of payload data + aqpsk.code_rate = 0.5; + aqpsk.framesize = 1152; % number of bits in LDPC encoded frame (data plus parity bits) + aqpsk.Ndatabits = aqpsk.framesize*aqpsk.code_rate; + aqpsk.Rbcoded = aqpsk.Rbdata/aqpsk.code_rate; % bit rate (Hz) of LPDC coded data + aqpsk.Rf = aqpsk.Rbcoded/aqpsk.framesize; % frame rate (Hz) + aqpsk.bits_per_symb = 2; % QPSK has two bits per symbol + aqpsk.Rscoded = aqpsk.Rbcoded/aqpsk.bits_per_symb; % symbol rate of LDPC coded data + aqpsk.Nsymb = aqpsk.framesize/aqpsk.bits_per_symb; % number of coded data symbols/frame + aqpsk.Npilotstep = 8; % number of data symbols between each pilot symbol + + aqpsk.Npilotsframe = (aqpsk.framesize/aqpsk.bits_per_symb)/aqpsk.Npilotstep; + if aqpsk.Npilotsframe != floor(aqpsk.Npilotsframe) + error("Npilotsframe must be an integer"); + end + + aqpsk.Nsymbpilot = aqpsk.Nsymb + aqpsk.Npilotsframe; % total number of symbols per frame including pilots + aqpsk.Rs = aqpsk.Rf*aqpsk.Nsymbpilot; % total symbol rate (Hz) + aqpsk.pilots = ones(1, aqpsk.Npilotsframe); + aqpsk.Np = 2; % number of pilots used for phase estimation + aqpsk.rx_pilot_buf = zeros(1,aqpsk.Np); + + % Init LDPC -------------------------------------------------------------------------- + + currentdir = pwd; + addpath '/home/david/tmp/cml/mat' % assume the source files stored here + cd /home/david/tmp/cml + CmlStartup % note that this is not in the cml path! + cd(currentdir) + + mod_order = 4; + modulation = 'QPSK'; + mapping = 'gray'; + demod_type = 0; + decoder_type = 0; + max_iterations = 100; + + code_param = ldpc_init(aqpsk.code_rate, aqpsk.framesize, modulation, mod_order, mapping); + assert(code_param.data_bits_per_frame == aqpsk.Ndatabits); + +endfunction + + +function sim_out = run_simulation(sim_in) + Ntrials = sim_in.Ntrials; + EsNodBvec = sim_in.EsNodBvec; + verbose = sim_in.verbose; + phase_offset = sim_in.phase_offset; + phase_est_en = sim_in.phase_est_en; + verbose = sim_in.verbose; + + rand('state',1); + randn('state',1); + + % Init modem and LPDC ---------------------------------------------------------------- + + [aqpsk code_param] = init_modem_ldpc; + + Nsymb = aqpsk.Nsymb; + Nsymbpilot = aqpsk.Nsymbpilot; + + % Start simulation ------------------------------------------------------------------- + + for ne = 1:length(EsNodBvec) + EsNodB = EsNodBvec(ne); + EsNo = 10^(EsNodB/10); + variance = 1/EsNo; + + Tbits = Terrs_uc = Terrs = Ferrs = 0; + + % Encode a bunch of frames + + for nn = 1: Ntrials + tx_bits = round(rand(1, aqpsk.Ndatabits)); + [tx_codeword, tx_coded_symb] = ldpc_enc(tx_bits, code_param); + symbpilot_tx = insert_pilots(tx_coded_symb, aqpsk.pilots, aqpsk.Npilotstep); + + noise = sqrt(variance*0.5)*(randn(1,aqpsk.Nsymbpilot) + j*randn(1,aqpsk.Nsymbpilot)); + symbpilot_rx = symbpilot_tx * exp(j*phase_offset) + noise; + + if phase_est_en + symbpilot_rx = correct_phase_offset(aqpsk, symbpilot_rx); + end + rx_coded_symb = remove_pilots(symbpilot_rx, aqpsk.pilots, aqpsk.Npilotstep); + rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_coded_symb, EsNo); + + % measure coded and uncoded errors + + errors_positions = xor(tx_bits, rx_codeword(1:aqpsk.Ndatabits)); + Nerrs = sum(errors_positions); + + rx_bits_uncoded = zeros(1, aqpsk.Ndatabits); + for s=1:Nsymb*aqpsk.code_rate; + rx_bits_uncoded(2*(s-1)+1:2*s) = qpsk_demod(rx_coded_symb(s)); + end + errors_positions = xor(tx_bits, rx_bits_uncoded); + Nerrs_uc = sum(errors_positions); + + if verbose == 2 + % print "." if frame decoded without errors, 'x' if we can't decode + + if Nerrs > 0, printf('x'), else printf('.'), end + if (rem(nn, 50)==0), printf('\n'), end + end + + if Nerrs > 0, Ferrs = Ferrs + 1; end + Terrs = Terrs + Nerrs; + Terrs_uc = Terrs_uc + Nerrs_uc; + Tbits = Tbits + aqpsk.Ndatabits; + end + + if verbose + printf("EsNodB: %3.2f BER: %f Tbits: %d Terrs: %d Ferrs: %d Terrs_uc: %d\n", EsNodB, Terrs/Tbits, Tbits, Terrs, Ferrs, Terrs_uc); + end + + sim_out.Tbits(ne) = Tbits; + sim_out.Terrs(ne) = Terrs; + sim_out.Terrs_uc(ne) = Terrs_uc; + sim_out.Ferrs(ne) = Ferrs; + sim_out.BER(ne) = Terrs/Tbits; + sim_out.FER(ne) = Ferrs/Ntrials; + sim_out.BER_uc(ne) = Terrs_uc/Tbits; + end + + sim_out.code_rate = aqpsk.code_rate; +end + + +% ---------------------------------------------------------------------- + + +function symbol_rate_curves + sim_in.phase_est_en = 1; + sim_in.phase_offset = 0; + sim_in.verbose = 1; + sim_in.EsNodBvec = -2:10; + sim_in.Ntrials = 10; + + sim_out = run_simulation(sim_in); + + EbNodB = sim_in.EsNodBvec - 10*log10(2); % QPSK has two bits/symbol + uncoded_BER_theory = 0.5*erfc(sqrt(10.^(EbNodB/10))); + + figure(1) + clf + semilogy(EbNodB, uncoded_BER_theory,'r;uncoded QPSK theory;') + hold on; + semilogy(EbNodB, sim_out.BER_uc,'r+;uncoded QPSK simulated;') + semilogy(EbNodB-10*log10(sim_out.code_rate), sim_out.BER+1E-10,'g;LDPC coded QPSK simulated;'); + hold off; + grid('minor') + xlabel('Eb/No (dB)') + ylabel('BER') + axis([min(EbNodB) max(EbNodB) min(uncoded_BER_theory) 1]) + +endfunction + + +% We are using a 3rd party modulator, this function generates bits +% that can be passed to it. It's organised as a file of 8 bit bytes +% MSB is sent first. Each pair of bits is mapped to phases as: +% +% MSB LSB Phase +% 0 0 0 +% 0 1 90 +% 1 1 180 +% 1 0 270 + +function generate_modulator_input_file(filename, seconds) + + [aqpsk code_param] = init_modem_ldpc; + + Nframes = floor(seconds/aqpsk.Rf); + Nsecs = Nframes*aqpsk.Rf; + Nbitsframe = aqpsk.Nsymbpilot*aqpsk.bits_per_symb; + Nbytesframe = Nbitsframe/8; + + printf("Frames: %d Seconds: %3.1f QPSK Symb Rate: %5.2f\n", Nframes, Nsecs, aqpsk.Rs); + printf("Bit/frame: %d Packed Bytes/frame: %4.1f\n", Nbitsframe, Nbytesframe); + + fbit = fopen(filename,"wb"); + + for nn = 1:Nframes + tx_bits = round(rand(1, aqpsk.Ndatabits)); + [tx_codeword, tx_coded_symb] = ldpc_enc(tx_bits, code_param); + symbpilot_tx = insert_pilots(tx_coded_symb, aqpsk.pilots, aqpsk.Npilotstep); + + % demodulate QPSK symbols back to bits + + tx_frame = zeros(1, aqpsk.Nsymbpilot*aqpsk.bits_per_symb); + for s=1:aqpsk.Nsymbpilot + tx_frame(2*(s-1)+1:2*s) = qpsk_demod(symbpilot_tx(s)); + end + packed_tx_frame = packmsb(tx_frame); + fwrite(fbit, packed_tx_frame, "uchar"); + end + + fclose(fbit); + +endfunction + +% --------------------------------------------------------------------------------- + +generate_modulator_input_file("modinputbits_v0.1.bin", 300) diff --git a/codec2/branches/0.7/octave/trellis.m b/codec2/branches/0.7/octave/trellis.m new file mode 100644 index 00000000..3838fd37 --- /dev/null +++ b/codec2/branches/0.7/octave/trellis.m @@ -0,0 +1,523 @@ +% trellis.m +% David Rowe June 2015 +% +% Testing ideas for trellis decoding of codec parameters. Uses +% soft decision information, probablility of state transitions, +% and left over redundancy to correct errors on codec parameter +% reception. +% +% [X] Add probability of transition +% [X] Will this mess up a perfectly received signal, i.e. all +% codewords perfectly received. This should dominate prob +% calc (with small No) +% [ ] can we measure erroneous decodes? Whn it makes it worse? +% + like all FEC, at some point, it will get a poorer BER +% + can we drawa curve of coded versus uncoded errors? +% [ ] test with actual data, add errors, see if it corrects any +% [ ] can we draw a trellis with actual values? +% +% Note we need SD bits and natural binary order encoding, for example +% ./c2enc 700 ../../raw/ve9qrp_10s.raw ../../octave/ve9qrp_10s.bit --softdec --natural + +graphics_toolkit ("gnuplot"); +more off; +randn('state',1); + +% Before I couldn't even sp3ll functional programmer. Now I are one ;) + +function [bits_per_frame bit_fields] = codec2_700_bit_fields + bits_per_frame = 28; % number of bits/frame for "700" mode + bit_fields = [1 5 3 3 2 4 3 3 2 2]; % number of bits in each field for "700" mode + % voiced, Wo, energy, LSP 1..6, 2 spare +endfunction + +% builds a metric of trasnition probablilities for each codec field (model parameter) + +function [tp codewords] = build_tp(bitstream_filename) + [bits_per_frame bit_fields] = codec2_700_bit_fields; + nfields = length(bit_fields); + + % load encoded speech file (one float per bit) + + fbitstream = fopen(bitstream_filename, "rb"); + bitstream = fread(fbitstream, "float32"); + fclose(fbitstream); + nframes = floor(length(bitstream)/bits_per_frame); + bitstream = bitstream < 0; + + % extract each field (model parameter) for bit stream + + codewords = zeros(nframes,nfields); + for f=1:nframes + aframe = bitstream((f-1)*bits_per_frame+1:f*bits_per_frame); + field = 1; + st = bit_fields(field); + for l=1:nfields + nbits = bit_fields(field); + %printf("st: %d %d\n", st, st+nbits-1); + codeword = aframe(st:st+nbits-1)'; + %printf("codeword: %d\n", codeword); + codewords(f,l) = sum(codeword .* 2.^(nbits-1:-1:0)); + %printf("nbits: %d lsp(%d, %d) = %d\n", nbits, f, l, codewords(f,l)); + st += nbits; + field++; + end + end + + % determine transition probablilities of each codeword + % state at time n, state a time n+1 + % prob must add to 1 + % so for every state, of every codeword, compute histogram of + % transition probabilities + + tp = zeros(32,32,nfields); + for f=1:nframes-1 + for l=1:nfields + acodeword = codewords(f,l); + bcodeword = codewords(f+1,l); + %printf("%d %d %d %d\n", f, l, acodeword, bcodeword); + tp(acodeword+1,bcodeword+1,l)++; + end + end +endfunction + + +% converts a decimal vlaue to a soft dec binary value + +function c = dec2sd(dec, nbits) + + % convert to binary + + c = zeros(1,nbits); + for j=0:nbits-1 + mask = 2.^j; + if bitand(dec,mask) + c(nbits-j) = 1; + end + end + + % map to +/- 1 + + c = 1 - 2*c; +endfunction + +% y is vector of +/- 1 soft decision values for 0,1 transmitted bits + +function lnp = ln_prob_of_tx_codeword_c_given_rx_codeword_y(y) + nbits = length(y); + np = 2.^nbits; + + % work through all possible received codeworks and determine probability + % given a number of bits + + lnp = zeros(1,np); + for i=0:np-1 + + c = dec2sd(i,nbits); + + % probability calculation for this i + + lnp(i+1) = sum(y .* c); + end + +endfunction + + +% y is the received soft decision codedwords, each row is one codeword in time +% tp is the transition probabilities, each row is the start state +% returns the most likely transitted codeword c + +function c = find_most_likely_codeword(y, tp, nstages, verbose) + [ncodewords nbits] = size(y); + nstates = 2^nbits; + n = ones(1,nstages); + + lnp = zeros(nstages, nstates); + for s=1:nstages + lnp(s,:) = ln_prob_of_tx_codeword_c_given_rx_codeword_y(y(s,:)); + end + + if verbose + % printf received codewords + + printf("rx_codewords:\n"); + for r=1:ncodewords + for c=1:nbits + printf("%7.2f", y(r,c)); + end + printf("\n"); + end + + % print probability of each rx codeword table + + printf("\nProbability of each tx codeword:\n"); + printf("tx_codeword stage\n"); + printf("bin dec "); + for s=1:nstages + printf(" %9d", s); + end + printf("\n"); + + for i=1:nstates + printf("%3s %2d ", dec2bin(i-1,nbits), i-1); + for s=1:nstages + printf(" %9.2f", lnp(s, i)); + end + printf("\n"); + end + printf("\n"); + + printf("\nTransition Probability table:\n"); + printf("state/next_state\n"); + for r=1:nstates + for c=1:nstates + printf("%7.2f", tp(r,c)); + end + printf("\n"); + end + printf("\n"); + end + + % determine probability of each path + % (prob of start state)(prob of transition)(prob of next state) + % cycle through all possibilities of states + % state variable for possible state + % step through them exhaustively + + if verbose + printf("Evaulation of all possible paths:\n"); + printf("tx codewords\n"); + printf(" n"); + for s=1:nstages-1 + printf(" n+%d", s); + end + printf(" "); + for s=1:nstages + printf(" lnp(%d) ", s-1); + if s < nstages + printf(" tp(%d,%d) ", s-1,s); + end + end + printf(" prob max_prob\n"); + end + + max_prob = -100; + + do + + % add up probabilities for this path + + if verbose + for s=1:nstages + printf("%4d", n(s)-1); + end + printf(" "); + end + + prob = 0; + for s=1:nstages + prob += lnp(s, n(s)); + if verbose + printf("%8.2f ", lnp(s, n(s))); + end + if s < nstages + prob += tp(n(s),n(s+1)); + if verbose + printf("%8.2f ", tp(n(s),n(s+1))); + end + end + end + + if (prob > max_prob) + max_prob = prob; + max_n = n; + end + + if verbose + printf("%9.2f %9.2f\n", prob, max_prob); + end + + % next path + + s = nstages; + n(s)++; + while (s && (n(s) == (nstates+1))) + n(s) = 1; + s--; + if s > 0 + n(s)++; + end + end + until (sum(n) == nstages) + + c = max_n((nstages+1)/2) - 1; + if verbose + printf("\nMost likely path....: "); + for s=1:nstages + printf("%4d", max_n(s)-1); + end + printf("\nMost likely codeword: %4d\n", c); + end +endfunction + + +% Simulations --------------------------- + +function [dec_hat dec_simple_hat dec_tx_codewords] = run_test(tx_codewords, transition_probabilities, nstages, var, verbose) + [frames nbits] = size(tx_codewords); + nerrors = 0; + nerrors_simple = 0; + tbits = 0; + nstates = 2.^nbits; + + rx_codewords = tx_codewords + sqrt(var)*randn(frames, nbits); + dec_hat = dec_simple_hat = dec_tx_codewords = zeros(1,frames); + + ns2 = floor(nstages/2); + for f=ns2+1:frames-ns2 + tx_bits = tx_codewords(f,:) < 0; + dec_tx_codewords(f) = sum(tx_bits .* 2.^(nbits-1:-1:0)); + dec_hat(f) = find_most_likely_codeword(rx_codewords(f-ns2:f+ns2,:)/(2*var),log(transition_probabilities+0.001), nstages, verbose); + rx_bits = dec2sd(dec_hat(f), nbits) < 0; + rx_bits_simple = rx_codewords(f,:) < 0; + dec_simple_hat(f) = sum(rx_bits_simple .* 2.^(nbits-1:-1:0)); + + nerrors += sum(xor(tx_bits, rx_bits)); + nerrors_simple += sum(xor(tx_bits, rx_bits_simple)); + if verbose + printf("[%d] %d %d\n", f, nerrors, nerrors_simple); + end + tbits += nbits; + end + + EbNodB = 10*log10(1/(2*var)); + printf("Eb/No: %3.2f dB nerrors %d %d BER: %3.2f %3.2f std dev: %3.2f %3.2f\n", + EbNodB, nerrors, nerrors_simple, nerrors/tbits, nerrors_simple/tbits, + std(dec_tx_codewords - dec_hat), std(dec_tx_codewords - dec_simple_hat)); + +endfunction + + +% Single point test, print out tables + +function test_single + tp = [1 0 0 0; 1 0 0 0; 1 0 0 0; 1 0 0 0]; + nstages = 3; + var = 0.5; + verbose = 1; + + tx_codewords = [1 1; 1 1; 1 1]; + run_test(tx_codewords, tp, nstages, var, verbose); +endfunction + + +% plot a trajectory of codewords, to help test "distance" is better using trellis than simple decoding + +function test_traj(tx_codewords, tp, nstages, var, verbose) + [frames nbits] = size(tx_codewords); + nstates = 2.^nbits; + + s = sum(tp+0.001,2); + [r c] = size(tp); + for i=1:r + tp(i,:) /= s(i); + end + + [dec_hat dec_simple_hat dec_tx_codewords] = run_test(tx_codewords, tp, nstages, var, verbose); + + figure(1); + subplot(211) + stem(dec_tx_codewords - dec_hat) + axis([1 frames -nstates/2 nstates/2]); + title('Trellis Decoding'); + subplot(212) + stem(dec_tx_codewords - dec_simple_hat); + axis([1 frames -nstates/2 nstates/2]); + title('Simple Decoding'); + + figure(2) + tp + length(1:nstates) + mesh(1:nstates,1:nstates,tp) + ylabel('current state'); + xlabel('next state'); +endfunction + + +% A contrived trajectories to check out the idea + +function simple_traj + %tp = [1 0 0 0; 1 0 0 0; 1 0 0 0; 1 0 0 0]; + tp = [0.5 0.25 0 0; 0.25 0.5 0.25 0; 0 0.25 0.5 0.25; 0 0 0.25 0.5]; + nstages = 3; + var = 0.5; + verbose = 0; + nbits = 2; + frames = 25; + + tx_codewords = ones(frames, nbits); + test_traj(tx_codewords, tp, nstages, var, verbose) +endfunction + + +% Run through a trajectory, say from a different file to what we +% trained with. Plot trajectory before and after passing through +% our decoder. Try first with no noise, then with noise. + +function test_codec_model_parameter(bitstream_filename, model_param) + [bits_per_frame bit_fields] = codec2_700_bit_fields; + + % load training data + + printf("loading training database and generating tp .... "); + [tp codewords_train] = build_tp("hts.bit"); + printf("done\n"); + + % load test data + + printf("loading test database .... "); + [tp_test codewords_test] = build_tp(bitstream_filename); + printf("done\n"); + + % run test data through + + nbits = bit_fields(model_param); + nstates = 2.^nbits; + nstages = 3; + var = 0.25; + verbose = 0; + frames = length(codewords_test); + %frames = 100; + + tx_codewords = zeros(frames, nbits); + for f=1:frames + dec = codewords_test(f, model_param); + tx_codewords(f,:) = dec2sd(dec, nbits); + end + + test_traj(tx_codewords, tp(1:nstates,1:nstates,model_param), nstages, var, verbose); + + figure(3) + plot(codewords_test(1:frames, model_param)) + +if 0 + figure(4); + fs=fopen("../raw/ve9qrp_10s.raw","rb"); + s = fread(fs,Inf,"short"); + plot(s(1:320*frames)) + axis([1 320*frames -3E4 3E4 ]) +end +endfunction + + +% writes an output bitsream file with errors corrected +% replay with something like: +% $ ./c2dec 700 ../../octave/ve9qrp_10s_trellis.bit - --softdec --natural | play -t raw -r 8000 -s -2 - + +function process_test_file(bitstream_filename) + [bits_per_frame bit_fields] = codec2_700_bit_fields; + + % load training data + + printf("loading training database and generating tp .... "); + [tp codewords_train] = build_tp("hts.bit"); + printf("done\n"); + + % load test data + + printf("loading test database .... "); + [tp_test codewords_test] = build_tp(bitstream_filename); + printf("done\n"); + + nstages = 3; + var = 0.5; + verbose = 0; + frames = length(codewords_test); + %frames = 150; + + % set up output frames + + frames_out = zeros(1,frames*bits_per_frame); + frames_out_simple = zeros(1,frames*bits_per_frame); + + % run test data through model and trellis decoder + + % just pass these fields straight through + + %for mp=1:10 + for mp=[1 2 3 10] + nbits = bit_fields(mp); + + % pack parameters in SD format into output frame + + for i=1:frames + en = (i-1)*bits_per_frame + sum(bit_fields(1:mp)); + st = en - (nbits-1); + %printf("fr st: %d offset: %d st: %d en: %d\n", (i-1)*bits_per_frame, sum(bit_fields(1:mp)), st, en); + frames_out(st:en) = dec2sd(codewords_test(i, mp), nbits); + frames_out_simple(st:en) = dec2sd(codewords_test(i, mp), nbits); + %p += bit_fields(i); + end + end + + + % trellis decode these fields + + for mp=4:9 + nbits = bit_fields(mp); + nstates = 2.^nbits; + + printf("processing parameter: %d nbits: %d\n", mp, nbits); + + % normalise transition probability rows + + tpmp = tp(1:nstates,1:nstates, mp); + s = sum(tpmp+0.001,2); + [r c] = size(tpmp); + for i=1:r + tpmp(i,:) /= s(i); + end + + tx_codewords = zeros(frames, nbits); + for f=1:frames + dec = codewords_test(f, mp); + tx_codewords(f,:) = dec2sd(dec, nbits); + end + + [dec_hat dec_simple_hat dec_tx_codewords] = run_test(tx_codewords, tpmp, nstages, var, verbose); + + % pack decoded parameter in SD format into output frame + + for i=1:frames + en = (i-1)*bits_per_frame + sum(bit_fields(1:mp)); + st = en - (nbits-1); + frames_out(st:en) = dec2sd(dec_hat(i), nbits); + frames_out_simple(st:en) = dec2sd(dec_simple_hat(i), nbits); + end + + end + + % save frames out + + [tok rem] = strtok(bitstream_filename,"."); + fn_trellis = sprintf("%s_%3.2f_trellis%s",tok,var,rem); + fn_simple = sprintf("%s_%3.2f_simple%s",tok,var,rem); + printf("writing output files: %s %s for your listening pleasure!\n", fn_trellis, fn_simple); + + fbitstream = fopen(fn_trellis,"wb"); + fwrite(fbitstream, frames_out,"float32"); + fclose(fbitstream); + + fbitstream = fopen(fn_simple,"wb"); + fwrite(fbitstream, frames_out_simple,"float32"); + fclose(fbitstream); + +endfunction + +% uncomment one of the below to run a simulation + +%test_single +%simple_traj; +test_codec_model_parameter("ve9qrp_10s.bit", 6); +%process_test_file("ve9qrp_10s.bit") + diff --git a/codec2/branches/0.7/octave/twomixer.m b/codec2/branches/0.7/octave/twomixer.m new file mode 100644 index 00000000..0a718cb5 --- /dev/null +++ b/codec2/branches/0.7/octave/twomixer.m @@ -0,0 +1,38 @@ +% twomixer.m +% David Rowe Feb 2015 +% +% test program for combining signals from two mixers + +fc=1024; +Fs=8192; +[b a] = cheby2(6,40,[200 3000]/(Fs/2)); + +w1 = 2*pi*(fc/2)/(Fs/2); +w2 = 2*pi*(3*fc/2)/(Fs/2); +w3 = 2*pi*(5*fc/2)/(Fs/2); +wc = 2*pi*fc/(Fs/2); + +t = 0:(Fs-1); +s1 = cos(w1.*t); +s2 = cos(w2.*t); +s3 = cos(w3.*t); +s = s1 + s2 + s3; + +lo1 = cos(wc*t); +lo2 = cos(2*wc*t); +out1 = filter(b,a,s .* lo1); +out2 = filter(b,a,s .* lo2); + +S = fft(s); + +figure(1) +subplot(211) +plot(abs(S)); +subplot(212) +plot(angle(S)) + +figure(2) +subplot(211) +plot(abs(fft(out1))) +subplot(212) +plot(abs(fft(out2))) diff --git a/codec2/branches/0.7/octave/twotone.m b/codec2/branches/0.7/octave/twotone.m new file mode 100644 index 00000000..a20c5c5a --- /dev/null +++ b/codec2/branches/0.7/octave/twotone.m @@ -0,0 +1,52 @@ +% twotone.m +% David Rowe Aug 2012 +% Used to experiment with combining phase of two tones + +function cbphase + + Wo = 100.0*pi/4000; + L = floor(pi/Wo); + phi = zeros(1,L); + + % two harmonics + + a = 20; b = 21; + + % set up phases to whatever + + phi(a) = -pi; + phi(b) = -pi/2; + + % synthesis the two-tone signal + + N = 16000; + Nplot = 250; + s = zeros(1,N); + + for m=a:b + s_m = cos(m*Wo*(0:(N-1)) + phi(m)); + s = s + s_m; + endfor + + % now our theory says that this signal should be the same perceptually + + phi_(a) = (phi(a) - phi(b))/2; + phi_(b) = (phi(b) - phi(a))/2; + + s_ = zeros(1,N); + for m=a:b + s_m = cos(m*Wo*(0:(N-1)) + phi_(m)); + s_ = s_ + s_m; + endfor + + % plot them and see if envelope has the same phase, but "carriers" + % have different phase + + figure(1); + clf; + subplot(211); + plot(s(1:Nplot)); + subplot(212); + plot(s_(1:Nplot),'r'); +endfunction + diff --git a/codec2/branches/0.7/octave/twotone1.m b/codec2/branches/0.7/octave/twotone1.m new file mode 100644 index 00000000..9f36c68d --- /dev/null +++ b/codec2/branches/0.7/octave/twotone1.m @@ -0,0 +1,76 @@ +% twotone1.m +% David Rowe Aug 17 2012 +% +% Used to experiment with combining phase of two tones. This version +% sets up a complete synthetic speech signal then tries to combine the +% phase of high frequency tones. Lets see if we can do this and keep perceptual +% nature of signal the same. + +function twotone1 + + % hts1a frame 47 + + Wo = 0.093168; + L = 33; + %A = [69.626907 460.218536 839.677429 2577.498047 972.647888 712.755066 489.048553 364.830536 409.230652 371.767487 489.112854 893.127014 2447.596680 752.878113 475.720520 234.452271 248.161606 232.171051 202.669891 323.914490 678.749451 362.958038 211.652512 170.764435 148.631790 169.261673 272.254150 176.872375 67.344391 99.022301 60.812035 34.319073 14.864757]; + A = zeros(1,L)*100; + phi = [1.560274 1.508063 -1.565184 1.289117 -2.547365 1.412528 -1.303992 3.121130 1.087573 -1.158161 -2.928007 0.995093 -2.614023 0.246136 -2.267406 2.143802 -0.273431 -2.266897 1.685171 -0.668712 2.699722 -1.151891 2.406379 -0.046192 -2.718611 0.761067 -2.305014 0.133172 -1.428978 1.492630 -1.668385 1.539734 -1.336615]; + %phi = zeros(1,L); + st = floor(L/2); + %st = 1; + + A(st:st+5) = 1000; + + % now set up phase of signal with phase of upper frequency harmonic + % pairs combined + + phi_ = phi; + for m=floor(L/2):2:L + phi_(m) = (phi(m) - phi(m+1))/2; + phi_(m+1) = (phi(m+1) - phi(m))/2; + %phi_(m+1) = 0; + end + + % synthesise the signals + + N = 16000; + Nplot = 250; + + s = zeros(1,N); + for m=st:L + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi(m)); + s = s + s_m; + endfor + + s_ = zeros(1,N); + for m=st:L + s_m = A(m)*cos(m*Wo*(0:(N-1)) + phi_(m)); + s_ = s_ + s_m; + endfor + + % plot them, expect to see similar time domain waveforms + + figure(1); + clf; + subplot(211); + plot(s(1:Nplot)); + subplot(212); + plot(s_(1:Nplot),'r'); + + figure(2); + clf; + subplot(211); + plot(s(1:Nplot)-s_(1:Nplot)); + + % save to disk + + gain = 1; + fs=fopen("twotone1_orig.raw","wb"); + fwrite(fs,gain*s,"short"); + fclose(fs); + fs=fopen("twotone1_comb.raw","wb"); + fwrite(fs,gain*s_,"short"); + fclose(fs); + +endfunction + diff --git a/codec2/branches/0.7/octave/tximage.m b/codec2/branches/0.7/octave/tximage.m new file mode 100644 index 00000000..f723e174 --- /dev/null +++ b/codec2/branches/0.7/octave/tximage.m @@ -0,0 +1,40 @@ +% tximage.m +% David Rpowe Sep 2015 + +% Say we have two signals from a mixer, at f_lo +/- f_if +% We attenuate one by 20dB with a BPF +% We then pass through a non linear amp +% Note non linearities are tricky to simulate as sign() gives +% us a lot of HF harmonics that aliased back down. +% +% However, it does appear that non-linear PA(sign) only supresses image +% by another 6dB. So mixing up does have it's problems compared +% to direct generation. A softer limiter (sqrt) seems to do a better job. + +fs = 1E4; +f_rf = 146; +f_if = 10.7; +f_lo = f_rf - f_if; + +f_rf1 = f_if + f_lo; +f_rf2 = f_if - f_lo; + +a_rf1 = 1; +a_rf2 = 0.1; + +t = 1:fs; + +sig_rf = a_rf1*cos(2*pi*t*f_rf1/fs) + a_rf2*cos(2*pi*t*f_rf2/fs); +sig_rf_clip = sign(sig_rf).* sig_rf .^ 1/2; +b = fir1(100, f_rf/fs); +sig_rf_clip_filter = filter(b,1,sig_rf_clip); + +figure(1); +subplot(211) +plot(sig_rf(1:1000)) +subplot(212) +plot(sig_rf_clip_filter(1:1000)) +figure(2) +plot(20*log10(abs(fft(sig_rf_clip_filter)))) +axis([1 1000 0 80]) +grid diff --git a/codec2/branches/0.7/octave/undersample.m b/codec2/branches/0.7/octave/undersample.m new file mode 100644 index 00000000..1bfbf38b --- /dev/null +++ b/codec2/branches/0.7/octave/undersample.m @@ -0,0 +1,26 @@ +% undersample.m +% David Rowe 5 Nov 2012 +% Testing algorithms for plotting undersampled data for fdmdv2 waveform displays + +fs=fopen("../raw/hts1a.raw","rb"); +s = fread(fs,Inf,"short"); + +Fs1=8000; +Fs2=200; + +M=Fs1/Fs2; + +samples=length(s)/M; +s1=zeros(1,2*samples); +for b=1:samples + st = (b-1)*M + 1; + en = b*M; + s1(2*b-1) = max(s(st:en)); + s1(2*b) = min(s(st:en)); +end + +subplot(211) +plot(s) +subplot(212) +plot(s1); + diff --git a/codec2/branches/0.7/octave/vhf_pa.m b/codec2/branches/0.7/octave/vhf_pa.m new file mode 100644 index 00000000..4b5486f4 --- /dev/null +++ b/codec2/branches/0.7/octave/vhf_pa.m @@ -0,0 +1,111 @@ +% vhf_pa.m +% +% David Rowe Dec 2015 +% +% Working for 0.5W VHF PA + +rfdesign; + +% BFQ19 Vce=5V Ic=50mA. These are small signal S-params, +% which (according to "RF Cicruit Design") are not valid. +% However I need to start somewhere. + +S11 = 0.324*exp(j*(-158.1)*pi/180); +S12 = 0.031*exp(j*(75.9)*pi/180); +S21 = 19.693*exp(j*(102.7)*pi/180); +S22 = 0.274*exp(j*(-74.6)*pi/180); + +% Lets check stability + +Ds = S11*S22-S12*S21; +Knum = 1 + abs(Ds)^2 - abs(S11)^2 - abs(S22)^2; +Kden = 2*abs(S21)*abs(S12); +K = Knum/Kden +figure(1); +clf +scCreate; + +if K < 1 + C1 = S11 - Ds*conj(S22); + C2 = S22 - Ds*conj(S11); + rs1 = conj(C1)/(abs(S11)^2-abs(Ds)^2); % centre of input stability circle + ps1 = abs(S12*S21/(abs(S11)^2-abs(Ds)^2)); % radius of input stability circle + rs2 = conj(C2)/(abs(S22)^2-abs(Ds)^2); % centre of input stability circle + ps2 = abs(S12*S21/(abs(S22)^2-abs(Ds)^2)); % radius of input stability circle + + s(1,1)=S11; s(1,2)=S12; s(2,1)=S21; s(2,2)=S22; + plotStabilityCircles(s) +end + + +% determine collector load Rl for our desired power output + +if 0 +P = 0.5; +Vcc = 5; +w = 2*pi*150E6; + +Rl = Vcc*Vcc/(2*P); +end +Rl = 10; + +% choose gammaL based on Rl + +zo = Rl/50; +[magL,angleL] = ztog(zo); +gammaL = magL*exp(j*angleL*pi/180); + +% calculate gammaS and Zi and plot + +gammaS = conj(S11 + ((S12*S21*gammaL)/(1 - (gammaL*S22)))); +[zi Zi] = gtoz(abs(gammaS), angle(gammaS)*180/pi,50); + +scAddPoint(zi); +scAddPoint(zo); + +% design Pi network for matching Rl to Ro, where Ro > Rl +% +% /---+-Xs1-Xs2-+---\ +% | | | | +% Rl Xp1 Xp2 Ro +% | | | | +% \---+---------+---/ +% +% highest impedance used to define Q of pi network and determine R, +% the "virtual" impedance at the centre of the network, whuch is smaller +% than Rl and Ro + +Ro = 50; +Q = 3; +R = Ro/(Q*Q+1); + +Xp2 = Ro/Q; +Xs2 = Q*R; + +Q1 = sqrt(Rl/R - 1); +Xp1 = Rl/Q1; +Xs1 = Q1*R; + +Cp1 = 1/(w*Xp1); +Cp2 = 1/(w*Xp2); +Ls = (Xs1+Xs2)/w; + +printf("Output Matching:\n"); +printf(" Rl = %3.1f Ro = %3.1f\n", Rl, Ro); +printf(" Q = %3.1f virtual R = %3.1f\n", Q, R); +printf(" Xp1 = %3.1f Xs1 = %3.1f Xs2 = %3.1f Xp2 = %3.1f\n", Xp1, Xs1, Xs2, Xp2); +printf(" Cp1 = %3.1f pF Ls = %3.1f nH Cp2 = %3.1f pF\n", Cp1*1E12, Ls*1E9, Cp2*1E12); + +% design input matching network between 50 ohms source and 10 ohms at base + +Rb = 10; Rs = 50; + +[Xs Xp] = z_match(Rb, Rs); + +Lp = Xp/w; +Cs = 1/(w*Xs); + +printf("Input Matching:\n"); +printf(" Xs = %3.1f Xp = %3.1f\n", Xs, Xp); +printf(" Lp = %3.1f nH Cs = %3.1f pF\n", Lp*1E9, Cs*1E12); + diff --git a/codec2/branches/0.7/octave/vq b/codec2/branches/0.7/octave/vq new file mode 100644 index 00000000..d5ab5918 --- /dev/null +++ b/codec2/branches/0.7/octave/vq @@ -0,0 +1,10247 @@ +# Created by Octave 3.8.1, Sat Apr 23 08:58:51 2016 AEST +# name: vq +# type: matrix +# ndims: 3 + 256 20 2 + 1.085205426985832 + -0.4260300009189197 + 0.833577745236378 + 1.798373960816606 + 0.9935936444607169 + 0.1239833582287509 + 1.575157273987481 + 0.9540245374175702 + 0.3562009016948172 + 1.585644452239723 + 1.506294746166876 + 0.2396183532805597 + 1.367446280732269 + 1.282223720216575 + 1.162423214604796 + 0.5244164469952718 + 1.128835884692779 + 1.058918853547902 + 1.963632826547209 + 0.5811484562442362 + 1.120960795023191 + 1.293247932196338 + 0.8421615329424976 + 1.327956700632984 + 1.150131602897049 + 1.32240186352708 + 1.151653785065956 + 0.4043141675059787 + -0.605854891571997 + 0.5664167394483143 + -0.7537298690327013 + 1.049449161804654 + 0.5218464074650003 + 1.494541250873327 + 0.8342264875867933 + 0.9206540524095941 + 0.06472922157937634 + 0.7198209111919989 + 1.38273463666622 + 1.369195704270166 + 0.7200435399985342 + 0.4728514924142588 + 1.338670575504253 + 0.901349771652351 + 0.7221823774481055 + 1.05531832867729 + 1.122264649509382 + 0.03480813187567571 + 0.8704977954705367 + 0.3118300343783649 + 1.345816954855809 + 0.9902369196859547 + 1.630250359910498 + 0.9962379680208187 + 0.7860178377708859 + 1.405072623711622 + 0.04215045540948043 + 1.100604952014984 + 1.801940417320714 + 1.672902158942722 + 0.9189112275890299 + 1.073606509430072 + 0.7077106102247487 + 1.351518501029729 + 0.8198628050578108 + 1.233747356047938 + 1.867879182176302 + 1.16871953438174 + 0.5619271296279016 + 1.377194835765386 + -0.06310946462056462 + 1.193115849982975 + 0.3302970529535515 + 1.128793026714063 + 0.9728683717267995 + 1.387587258338834 + 1.244021687351402 + 0.6683606936174704 + 1.199485416480435 + 0.5956899153219491 + 0.3013694867793058 + 0.8655341870443748 + 0.2088344957654923 + 1.1447496470614 + 1.084164446118127 + 1.003149200094682 + 1.191560192626183 + 0.07486858283563912 + 0.7661458586347402 + 0.4866127826256495 + -0.1089155940953209 + 1.23959659930226 + 1.054183144345908 + 0.2504451195646863 + 0.8956884207647202 + 1.119249454883628 + 1.116978748635182 + 0.9513183172426499 + 0.1089893432612581 + 0.6032927070356664 + 1.223982221591883 + 1.252308815173021 + 0.5827306571168442 + 1.421065953702404 + 0.162963901404173 + 1.196233511235407 + 1.84581856021695 + 0.9869956389787488 + 0.1646961461119581 + 0.9850201800243675 + 1.429250808608257 + 0.9923260772179757 + 0.9590272370201224 + 0.5825501483605714 + 1.070845967907089 + 1.175383240709347 + 0.6499779705541643 + 0.3320598410515813 + 1.592125364047756 + -0.3139251676378877 + 0.2941683771906135 + 1.678238614064441 + -0.4402253102695204 + 1.311626010101525 + 1.230368944293766 + 1.118969630404878 + 0.4699109361369931 + 0.5566459218624169 + 0.3996167544525743 + 1.063017424039592 + 0.9065738165115017 + 1.274194918558561 + 1.226051793207517 + 1.195335954727556 + 0.5219409661767341 + -0.3567210160579476 + 0.2030643648479605 + 1.385132588724635 + 0.9158832967346469 + 0.9322888042239789 + 1.298607308549179 + 0.6104336622079205 + 1.112243563345926 + 1.520623715949573 + 0.9317177714797874 + 0.7712367063105167 + 1.340499022391671 + 1.304764024159155 + 0.4735061357092801 + 0.9625427325458471 + 1.136775254002388 + 0.4261374335150909 + 0.3337168222499328 + 0.9646263375973135 + 0.1382418388350582 + 1.142845116548473 + 0.8905004958914902 + 0.6352197854178532 + 0.5315973388091748 + 0.2762672232170045 + 0.7323883053221711 + 1.069700009254771 + 0.5773447972180785 + 0.6265539300205094 + 1.208723096926154 + 1.373557618988817 + 1.396848139856655 + 1.22644909332404 + 0.747423382879117 + 0.1923928104579403 + 0.2317151183086048 + 1.195158636439779 + 1.235985355812018 + 0.9547800158843198 + 0.8904454757455824 + 1.143257875740302 + 0.908286803400884 + 0.1941688834036181 + 0.3158243056857314 + 0.6849987277815992 + 0.6445369483172818 + 1.05538088978711 + 0.6030235309635322 + 1.486202280215748 + 1.396804660772058 + 1.150704097309296 + 0.6920213957251961 + 1.582203495857851 + 1.202025792169117 + 1.374999251582953 + 0.2288168689728823 + 0.4329608518584964 + 0.8464391637680514 + 1.135844763204482 + -0.1545900194782768 + 0.9567819848531226 + 1.374372950241175 + 1.333415099532475 + 1.200028477439384 + -1.0208946912861 + 1.334019146241362 + 0.5691948095784971 + 1.250417957983486 + 0.1606069495457166 + 1.351838776281039 + 0.09518343481973855 + 0.3320891202043986 + 1.650452578645842 + 1.569148456097603 + -0.09071912653151751 + 0.3264988095922111 + 0.8375894641356687 + 0.6559955317907418 + 1.149364426104217 + 0.8062962854345533 + 0.9188276660142149 + 0.3028421810952253 + 1.566145006462622 + 0.5822774136794752 + 1.069120717715464 + 1.721561396547623 + 0.856831005984519 + 0.5564137080731699 + 0.7153678821180693 + 0.853234505158737 + 0.603185994785441 + 1.186506259153193 + 1.148948504058279 + 0.6177590034489259 + 0.5760949222380469 + 1.855034211463561 + 0.9121147355845477 + 1.010718439207553 + 1.549735365386854 + 1.069655184913645 + -0.7295454638452006 + 0.8476706126547495 + 1.045201963428327 + 1.876209304797508 + 1.100098125226684 + 0.5449377727755268 + 1.393285124315972 + 0.3558090786406779 + 0.9881025017683388 + 1.093368419306702 + 0.448706447264993 + 0.911083453512061 + 1.15800556561816 + -0.4846742001392422 + 0.5454789417356526 + -0.02763772693410249 + 0.7899662745198055 + 1.086855284902688 + 0.5083938014690804 + 1.784614071563062 + 0.4955810910707088 + 0.6307896832511808 + -0.34177101856323 + 1.407977101362635 + 0.01089753717535649 + 0.8109156423843644 + 0.02157571365906377 + 0.7974501480560753 + 1.161677104060995 + 0.7449135184865795 + 1.335922577995176 + 1.618074115184736 + 0.5036808860872769 + 1.281621536264201 + 1.496512222586918 + 0.5656867946695433 + 0.6635578371625578 + 0.7769267716943143 + 0.7863318705349102 + -1.780978883369023 + -0.0334354168623605 + 0.6636862687063216 + 1.31953372409462 + 0.7679335906405473 + 1.357765462325111 + 1.002678487287578 + 1.312437664849832 + 0.8924926344549168 + 0.4636383638860451 + -0.4070912248841624 + 0.3217800893580187 + -0.05480191063438398 + 0.5704105297752942 + 0.5671989228695588 + 1.265425897803026 + 0.9479718237857699 + 0.8777643997522284 + 0.1431302574000071 + 0.6515151863984949 + 1.173472222357272 + 1.362655064101474 + 0.5580298125429235 + 0.6418980270774041 + 1.03039668193185 + 0.3594537068522266 + -0.04147042419107318 + 1.455218010598134 + 1.227033289641574 + 0.06992318109090488 + 0.3180324711899842 + -0.1495786011244451 + 0.9918971182481525 + 0.8774198930235823 + 1.721649383997356 + 0.9281742007128928 + 1.640992165953183 + 1.269750130001307 + 0.03069266092696008 + 0.3789038439191283 + 0.593613546633564 + 1.111480012530088 + 0.8286979077983071 + 1.18404324241428 + 0.7819017133615419 + 1.184090438751563 + 0.7659782497915133 + 1.0270864532279 + 1.828429658014905 + 0.7901410673132826 + 0.7366673489477884 + 1.154988816261634 + -0.5471812039524085 + 0.934981740816867 + 0.2371332570247094 + 1.0250163450453 + 1.27266423448643 + 1.454333079552459 + 0.5727768922154086 + 0.9771845066546033 + 0.9172197471647986 + 1.075563145199177 + 0.4384292666482437 + 1.239092406693795 + 0.210285117767336 + 0.8733612055335693 + 1.053824328003951 + 1.140078195008836 + 0.7905272592630922 + 0.7828638574028199 + 0.3800700405357779 + 0.04386828899833825 + 0.4448709339379409 + 1.175831673476218 + 0.5101567242836115 + 0.09582478057635176 + 0.5917407640130367 + 1.188218565713065 + 0.9963122522605247 + 0.9296892601798483 + 0.2641176647599591 + 0.03959598133926203 + 0.9551648406598405 + 1.0764477050855 + 0.1378738153867933 + 1.23353768813546 + -0.4889616350026407 + 0.8333605392781226 + 1.077043592755524 + 0.4993903680346781 + -0.1139168084620633 + 0.7914997890435082 + 1.061615511701903 + 0.7068251156389007 + 0.8895360567176563 + 0.9221606578157804 + 0.8720105612358751 + 1.146999585796198 + 0.2380133501973453 + 0.5057686048644131 + 1.479930515236531 + 0.01015620544596672 + 0.2431628777000853 + 1.702530222152529 + -0.6796910843532397 + 1.032776572059292 + 1.301342297641337 + 0.8143336069861939 + 0.7635151712808649 + 0.6362377313700681 + 0.4339276521621836 + 0.4802842872208226 + 0.3001502607473731 + 1.106077237434545 + 1.008263870942845 + 1.365542441935153 + 0.6790855740186382 + -0.0837459219137099 + 0.8732339782103199 + 1.640876156222111 + 0.9177915661396188 + 1.104421107680557 + 0.8853913828852079 + 0.4571773916694294 + 0.9094059065244827 + 1.587617533587789 + 0.1524648649046425 + 0.3692382822458569 + 1.242632785428377 + 1.320666722021657 + 0.6910286390838315 + 0.8196657398334 + 1.094117543461184 + 1.050573062644234 + -0.095843175006164 + 0.8439478073229337 + 0.01388520142811661 + 0.8525313241450097 + 0.7560187534936887 + 0.7163589419339997 + 0.48172955945087 + 0.3191282594036909 + 0.5887849395958622 + 1.073048278856649 + 0.6298813075484302 + 0.8494144146160413 + 1.119108071145198 + 0.5041467048651576 + 0.753953116677396 + 1.415463825758381 + 0.7543289699956602 + 0.1886565605608594 + 0.337384574159233 + 0.997230623170282 + 0.9040472605249359 + 0.4907711273324722 + 0.9061210546528722 + 1.156437217107255 + 0.4695398632675316 + -0.00085808420372521 + 0.1361669439466877 + 0.789467312307312 + 0.5997423085983093 + 0.6901869245440042 + 0.6159422966653133 + 1.199854198628586 + 0.8079953503366223 + 0.468524121850383 + 0.5324545493188838 + 0.8344982497659503 + 1.370319814607772 + 1.44131066853247 + 0.7407415623265214 + 0.05393103628695976 + 1.079745668684748 + 0.5729519871321513 + -0.1851074752298328 + 0.992944720430734 + 0.9115450331591136 + 1.370626836759575 + 0.4751961017836588 + -0.6822887887799577 + 1.355603094738513 + 0.7582980444714997 + 1.287305989858565 + 0.3103196025488943 + 1.421172024185723 + -0.03865357392167217 + 0.7292790541459703 + 1.503226353587898 + 0.5882138571631963 + -0.6093718430332411 + 0.1767394375474176 + 1.276766057212127 + 0.2680255519434074 + 1.12370254387008 + 0.398854116141619 + 1.137373259085501 + -0.3490926629910003 + 1.624321880009409 + 0.5226169241649171 + 0.9044285339583492 + 1.521669667354217 + 0.7912102844944133 + 0.4799761729696941 + 0.007198768056136138 + 1.118146053519841 + 0.6123216140984202 + 1.326185872147739 + 0.9124790581806869 + 0.04998935374131432 + 0.197000146554438 + 0.891152524397205 + 0.5822353455552293 + 0.3891121700178945 + 1.593699066012701 + 0.9369187911763287 + -0.4173953205770336 + 0.02815662236665207 + 1.263074340857436 + -0.4156518344072447 + 0.9024061343598681 + 0.08377464923872469 + 1.738787817003506 + 0.5177228046119318 + 1.132147362693591 + 1.279158205976386 + 0.7202975064986489 + 1.083485371159031 + 1.243643218383548 + -0.252741128821911 + 0.7413435329819636 + 0.4777693296936473 + 0.8402990100436456 + 1.01127993141735 + 0.1533121344864636 + 1.467708403340319 + 0.491607387702562 + 0.2813488729981752 + -0.23309774437551 + 0.8385025128809915 + 0.3270048984513226 + 0.8551646087377082 + 0.0510931504452391 + 0.2765658079493324 + 1.19487687416751 + 0.7330927106990655 + 0.4039208562877936 + 0.7509115681262256 + 0.2929882944647805 + 0.6622594713526353 + 0.8716985336118284 + 0.256385689857605 + 0.5761648585763438 + 0.5135305910284679 + 0.7367357125025655 + 1.893284660668191 + -0.1812633458814429 + 0.5535296184930434 + 0.7110951260347793 + 0.1472364235480178 + 0.821249306261171 + 0.4425183187837054 + 1.099118632151938 + 0.5697552691995635 + 0.9103172272666007 + -0.3505623944219689 + 0.3038726147938779 + 0.2766268157752633 + 0.4633144824118865 + 0.421873437147429 + 1.403668123763734 + 0.885456979305717 + 0.4495998966673143 + 0.1751816133102695 + 0.1420572593236852 + 1.023012905853923 + 0.6073508208973148 + 0.698487833169068 + 0.6488088673841286 + 0.5915845287078585 + -0.05177700993234245 + -0.2162361772648918 + 1.095833420194178 + 1.280856218535019 + 0.1730234086711988 + 0.1005129723860903 + -0.2376144855255936 + 0.4483192343799798 + 1.104287886446522 + 1.05196798440898 + 1.422049575253155 + 1.537352663766892 + 0.7500419081327695 + 0.03991494652899544 + 0.1034867659806852 + 0.4224085207772535 + 0.3864210672817945 + 0.3735747180645465 + 0.7765915223589677 + 0.3315281950696041 + 0.5683741364769683 + 0.2019063044164997 + 1.034269555873555 + 1.233685691705767 + 0.09881214847988599 + 0.2720142723998445 + 0.6198100476916732 + -0.4401429185734267 + 0.2989412982646393 + 0.1531713813109536 + 0.6256149735005488 + 0.2905363579030045 + 1.397726502355438 + 0.2616648818407552 + 0.4490368449109646 + 0.9163917663722386 + 1.089257583951409 + 0.5203423966116525 + 0.8826668740057446 + 0.5417175045725473 + 1.090892214419326 + 0.7454410916412249 + 0.7525217841302803 + 0.1226292710741966 + 1.030237066837245 + 0.2089646577463286 + -0.06084684303132043 + 0.9846655017994531 + 0.5153646593337698 + 0.2205181808919031 + 0.2146525528107585 + 0.4538487033213079 + 0.3112177429774014 + 0.6401051461257636 + 0.2233938908298634 + 0.2471328569943696 + -0.3118132717953503 + 1.011259948671065 + 0.8180977557926039 + 0.01109870254488479 + 0.9295340611245301 + -0.4471511869338353 + 0.2186642118804684 + 0.3410503815535691 + 0.2961312366333129 + -0.143295880948191 + 0.6570058907728265 + 0.3374478790259653 + 0.7164972147498678 + 0.4728493928151949 + 0.6309390863530263 + 0.9192287990009655 + 0.5236244132628847 + -0.01669515537818698 + 0.7359536567719464 + 0.7633933826108308 + 0.1505084066165529 + 0.03028416277848445 + 1.085764033307612 + -0.5202265832878327 + 0.7875814498506806 + 0.3028976076028166 + 0.3041742281687709 + 0.6305983965683244 + 0.3863647299097199 + 0.6091800798116837 + 0.2766290594885096 + -0.04164046469769212 + 1.095085939499609 + 0.7520161873439619 + 0.6899692417334078 + 0.722569043292997 + 0.1692090038495222 + 1.082199154298006 + 1.581671334352642 + 0.689404983899905 + 0.6840779222017123 + 0.8436653279709823 + 0.2662908234016441 + 0.981892759284849 + 1.134640943038094 + -0.2345715436513772 + 0.6178212925489196 + 0.4036932487417162 + 0.7952702641381866 + 0.5639573896008447 + 0.5993645140406432 + 0.7141580513604615 + 1.014012316351468 + -0.08744981314008972 + 1.063873115437658 + 0.1099034874188993 + 0.9950519710874927 + 0.1534889007169 + 0.05631190168031441 + 0.1748263357959901 + 0.165560369417498 + 0.4633308759715956 + 1.188905400442834 + 0.7731024403484956 + 0.8423415798127308 + 0.9718508042477025 + 0.2297467466333339 + -0.01320786123883487 + 0.5873563449277251 + 0.5910935104098086 + 0.3635749528124803 + 0.3343544719801193 + 1.18648459924689 + 0.4451694598362241 + 0.1324333660623244 + 1.084951896740999 + 0.3960438506447841 + 0.1749869325737155 + 0.02208594803615767 + 0.09245561966466478 + 1.122532226331501 + 0.4393539525729408 + 0.4115588600754834 + 0.2702758540323703 + 1.011999371548518 + 0.4948376043376667 + 0.07072665059510284 + 0.3109519530391471 + 0.08833859645953668 + 1.42027802339303 + 0.9341542146532245 + 0.4553619567468035 + -0.1411301391868214 + 1.056999637245755 + 0.2473749868663636 + -0.1674778939937979 + 0.4949894843141263 + 0.3037014956998224 + 1.043405348612228 + -0.02690205634125676 + -0.4006218991582415 + 0.7880313750703598 + 0.8392053130898005 + 0.8938116092151039 + 0.4481197017943047 + 1.044980745627303 + 0.0633474328942642 + 0.3676187329050571 + 0.8260672972308953 + 0.09198051118011895 + -0.4135806176956385 + 0.3550021274498011 + 0.9113941029960042 + 0.1252852590239979 + 0.6630493499094094 + 0.3076774479505871 + 0.2015842344325611 + -0.346834457601448 + 0.8287973613110869 + 0.2967238340679168 + 1.249776900632627 + 0.8378302025923385 + 0.2601815719430856 + 0.2421592762135072 + -0.2792952167765571 + 1.016400334668337 + 0.0916798184791715 + 0.4392572064535232 + 0.4227332600248574 + -0.1001271299425782 + -0.001465314706970619 + 0.2560201957554942 + 0.3296530897657324 + 0.1565518292519268 + 1.261770984934702 + 0.3885726181860199 + -0.1954207667055181 + -0.2052101948457193 + 1.144868702233546 + 1.298048107673848 + 0.7249741552686874 + -0.08176434161962366 + 1.176339530411192 + 0.6407595791199964 + 0.8844590668365837 + 0.6642328057538459 + 0.848163608448612 + 0.6932933316219306 + 0.7959734189807569 + -0.1667762824316838 + 1.286512244363518 + 0.6279406083841168 + 0.8883628309026455 + 0.9414864655393888 + 0.2784164795536057 + 0.7809719251837841 + 0.3649021998185719 + 0.1617608439534715 + -0.1337007970435923 + 0.05357396878826291 + -0.4123475197060653 + 0.6793419169334679 + 0.0531435473951218 + 0.08546646719549002 + 0.8467171554056512 + 0.2006091551971668 + 0.02207625831547735 + -0.2065546538260196 + -0.1500903968350547 + -0.1780567295704319 + 0.1747860566134954 + 0.02125819010347606 + 0.2164826363626913 + 0.1443591827454877 + 0.9803964077859239 + -1.780599153696266 + 0.2055912305732803 + 0.6887745530042322 + -0.01050806541979735 + -0.2426710690444304 + 0.1410483568277712 + -0.2006929997681248 + 0.8833631850914567 + 0.162520794689835 + 0.5527779486354782 + -0.3978712960120283 + 0.3437758311462648 + -0.007205974613345725 + 0.1841357965531394 + 0.09152585081054528 + 1.286508701564548 + 0.3655186020172489 + 0.316716706042257 + -0.3127458919964299 + -0.2094498284541832 + 0.7904908777949718 + -0.01086593359251741 + 0.8864233108894075 + 0.4630987816902309 + 0.3434295920993696 + -0.2792796618186488 + -0.2016090751399555 + 0.4244685847407725 + 1.262064526376716 + -0.08544915908117247 + 0.07717200318988543 + -0.2904135750963075 + 0.1095873134471235 + 0.8385397295204448 + 0.318490257369696 + 1.235507037818786 + 1.259099473202747 + 0.3947007258433206 + -0.008180057120502274 + -0.0361143889651698 + 0.4164480523231656 + -0.02334847607833782 + 0.06517205255138779 + 0.1618198171183014 + -0.2659533632859265 + -0.01562677004495009 + -0.1206358109498548 + 1.002757776307379 + 0.4986699392847478 + -0.1371903112173145 + -0.00344358633489329 + -0.07996003153263954 + -0.3379485137288289 + -0.03806474899354377 + 0.2683029250821991 + 0.4100228415034203 + -0.5108165651107379 + 1.184539416771237 + 0.1978249632565801 + -0.09630232711143173 + 0.5430847989065629 + 0.4074670926797942 + 0.4631484926382279 + 0.1088129743911087 + 0.6248848760480203 + 1.335482560719826 + 0.5155308620325403 + 0.06752770884254551 + -0.1248334783810167 + 0.3963970410539291 + -0.04969096370578793 + -0.1216187484590646 + 0.8689318195651347 + 0.08578933212809549 + 0.08798208804502958 + 0.1239523977696128 + 0.7575757543842648 + -0.5595989732992216 + 0.0622867847444411 + -0.2926542381256442 + 0.1580875827841728 + -0.425556755299803 + 1.289880604134823 + 0.3535913221615343 + -0.09873744696346339 + 0.5035922557411745 + -0.3769750284854071 + -0.2740109377625299 + 0.08237750806349588 + 0.2263722622510267 + -0.2518950618988852 + 0.6067018699476547 + -0.08611878074779186 + 0.9899446712432615 + 0.56646645492197 + 0.1011353098063996 + 0.6347240555798442 + -0.195088801537368 + -0.1654943782773581 + 0.9426980842944602 + 0.5010721927420557 + -0.02065723337935632 + -0.1873567752539188 + 0.4389198390611936 + -0.5307174645776235 + 0.5103471895505917 + -0.5719078828410628 + 0.2149994092751085 + 0.06942256938950482 + -0.09480109603957031 + 0.7856110736017079 + 0.1262729905621497 + -0.1242442642087571 + 0.7375115728397422 + 0.7289571746152353 + -0.06700990897760298 + 0.5820134850756077 + 0.192612145157865 + 0.4557109964282625 + 1.51341697909097 + 0.7253998697830548 + 0.1460115103717501 + 0.5642719127158798 + 0.08625007759573282 + 0.8566197096352928 + 0.8364491248658364 + -0.3513666162487823 + 0.5432105555615571 + -0.4289085218375293 + 0.08484774382517647 + 0.1045245386515451 + 0.1566853648593213 + 0.2079149196894243 + 0.4077901486435228 + 0.006353698137078662 + 1.168997355279365 + 0.1597654442842663 + 1.237495342298039 + -0.1510923183128803 + -0.3458940525314884 + -0.07979655864943636 + -0.01560096750891377 + 0.3022630572884595 + 0.6470884583341112 + 0.5607465349171387 + 0.5874337534730686 + 0.5187410585951379 + 0.09923649517267127 + -0.3903120574808259 + -0.2248925641470509 + 0.5022861897824493 + 0.4374504749438747 + 0.3313371562970333 + 0.7814655560905704 + 0.01544256774635527 + -0.1346611555543178 + 0.9649205799373766 + -0.07399090242506197 + 0.00216705002061529 + 0.1458209566043037 + 0.05173860838852241 + 0.8507228862081294 + 0.3320570498962878 + 0.1655384932336358 + -0.02728734826639537 + 0.691336705496105 + 0.3150476389121989 + -0.03357036370806174 + 0.1898216245312712 + -0.1342540497391477 + 0.7772548085734329 + 0.03422543205667956 + -0.05226192976806608 + -0.1849123430625171 + 0.3275105501377845 + 0.04307605486698986 + -0.131123603083785 + 0.07487897523238661 + 0.1296086875090163 + 0.2501117652645889 + -0.2469752436259501 + -0.3544171354949975 + 0.08169347749847211 + 0.5339569458487908 + -0.09703519674586708 + 0.7488798079926938 + 0.08679629241041764 + -0.07072096977100872 + -0.2971862572087856 + 0.1263912615773313 + -0.05568275635783676 + -0.3822170484681757 + 0.6091905020006767 + 0.1930470707969421 + 0.08467963438116037 + 0.05249402872623965 + 0.2494332525911941 + -0.3320851228066722 + -0.2403789133443307 + 0.003345438942484604 + 0.3176445946245712 + 1.208968052226298 + 0.1203616024566635 + -0.1936304993502403 + 0.2018677424059998 + -0.3857096249615873 + 0.4468458397728436 + -0.2453648163093229 + -0.4256714755667666 + 0.1389267737056973 + -0.01545153071922624 + -0.1413233554768697 + 0.147789392764825 + 0.1156480357397888 + 0.0266055205360948 + 0.6561921889029468 + 0.7010147506182437 + -0.2516907836458909 + 0.05665772882715631 + 0.7190474056023438 + -0.403927684259865 + 0.6010008006167838 + -0.1350583498082975 + 0.4163660158163784 + 0.5782030959359387 + 0.3523975447901436 + -0.347734778161943 + 0.5127491719291808 + -0.3351261666665789 + 0.250711139193513 + 0.04821676249691886 + 0.9861395396684846 + 0.2187220948755276 + 0.3511444826916622 + 0.4410497755064916 + 0.4556123632934783 + 0.1785487993615588 + 0.2588746056146861 + 0.2492336745272817 + -0.1150533905185065 + -0.4450561816044189 + -0.06993355636454991 + 0.09253844510767809 + -0.1000610640420145 + -0.0698313843763893 + 0.937320563935966 + -0.0467781576047443 + -0.1681224604784059 + -0.6348904503155944 + -0.3255593080943681 + -0.4085209807394772 + -0.1973597162255788 + -0.1207550566380952 + 0.01052399285950291 + -0.1848780649545811 + 0.3931454951158443 + 1.708587401263964 + 0.1815742073568385 + 0.3432258558580351 + -0.3235036466031508 + 0.1002580442394274 + -0.1656183374822657 + -0.5108101149367126 + 0.7029226243217359 + -0.1502954479250325 + 0.05155446529395855 + -0.3022605283953436 + 0.5006594548808039 + -0.1540169005448221 + -0.0808246526473457 + -0.06080349728458864 + 1.237949063220778 + 0.457988933458353 + -0.1983797881327917 + -0.1453660564807468 + -0.3645458471204732 + 0.6623087958585292 + -0.5191638331056148 + 0.730676729677982 + 0.454354417807533 + 0.244905553179521 + -0.4545438372434316 + -0.1777129740215161 + -0.09666991424093212 + 0.8612857352244105 + -0.2867503905402772 + 0.01147565153030176 + -0.3327065762902315 + -0.04614795914575914 + 0.1769359982094564 + -0.07447234559883557 + 0.6946784329695896 + 0.8512323210306233 + 0.1273929508353219 + -0.03714283970900223 + -0.1163562140248569 + 0.07905646190407437 + -0.2586250581226313 + 0.3106167704848445 + -0.1873673582250238 + -0.5676658815811136 + -0.3809431196943583 + 0.06176087555426465 + 0.6575358337549088 + -0.006769186530244102 + -0.1203960737346448 + -0.1094544844648559 + 0.1531586841524122 + -0.3214904782015948 + -0.2921953670052535 + 0.326382780315558 + 0.2417348463238819 + -0.5516588351271658 + 1.066164073381822 + 0.14324349480137 + -0.2733021473763657 + 0.206060754119072 + -0.02257933747166856 + 0.2768576353874935 + -0.2579005608332602 + 0.1801217548083397 + 1.084353873711691 + 0.3582093678938069 + -0.2916869832915906 + -0.3537129759545287 + -0.09869695728672255 + -0.1342763217983003 + -0.1435248816361132 + 0.538588215431827 + -0.1648167859173915 + -0.06048176695018438 + 0.01708217866334022 + 0.5826225897182519 + -0.8955426379811293 + -0.2145654505127193 + -0.5702901567777114 + 0.06182340425302407 + -0.4727413815038695 + 0.8668513674103833 + -0.2782503430951879 + -0.1368352825144238 + 0.2666864101935165 + -0.3559992263173706 + -0.5413058149479931 + -0.1907750299241658 + 0.09113609665269655 + -0.3366637410284195 + 0.1974660169012988 + -0.310940985712738 + 0.7591977595514805 + 0.6462592979786056 + -0.1249380157468614 + 0.1349792499000788 + -0.40097352887511 + -0.2663907703264866 + 0.6431491233037089 + 0.5477259895917688 + -0.1387607052964635 + -0.2325564654979926 + -0.01989557145425267 + -0.5983963836613112 + 0.27513653485933 + -0.8452115138518678 + 0.05263917292841345 + -0.1531721592418351 + -0.2878930384944877 + 0.4625364395796986 + 0.02948229076842242 + -0.1863083386357931 + 0.5301844345548528 + 0.4299777175923086 + -0.357440209921069 + 0.4446768916936731 + 0.2061364228902275 + -0.008035266959642419 + 1.00567185628664 + 0.6234505133315437 + -0.1063755889918123 + 0.213775422530152 + 0.1716216539220448 + 0.5969951111180575 + 0.3515302459721952 + -0.4956136864952044 + 0.04742685940225402 + -0.7257486741103216 + -0.2310899485637471 + -0.1499868791407927 + -0.2112420300445047 + -0.00566803311686644 + 0.1889455471317475 + 0.02645800593250528 + 0.4402766676397445 + 0.2016486637184166 + 1.098692300417186 + -0.3895102758514091 + -0.5062551631617818 + -0.09603580353709633 + 0.148616169977114 + 0.100593758335289 + 0.1763413543551331 + 0.3274952942433564 + 0.8240464416796819 + 0.3176467522397424 + -0.03187377697036982 + -0.623889657664299 + -0.4860291478329514 + 0.5281204436024102 + 0.06702912108261062 + 0.2380243775316523 + 0.5437146177333005 + -0.04966703248674136 + -0.1810109555153837 + 0.5573015738350131 + -0.4083930320187065 + -0.04320482925074265 + 0.1645640721387698 + 0.06119533902414419 + 0.7425524922816565 + 0.1299360824582844 + -0.00884558853432627 + -0.1015165767888688 + 0.6068938884710866 + -0.09923176919218805 + -0.09297497927202424 + 0.03586137208023404 + -0.2786570728969295 + 0.6649177733162734 + -0.3535585321565478 + -0.3390062989598818 + -0.2086173775975975 + -0.09920688041443682 + -0.02341421167161965 + -0.1471803450154052 + -0.3161453029449265 + 0.02391801391446054 + -0.04373650519867519 + -0.3397983188119051 + -0.3666108066854937 + -0.2162670349776072 + 0.2132530233673774 + -0.5116313544736404 + 0.5354757508904081 + -0.2877069810675497 + -0.1315602000375319 + -0.5317429707262271 + 0.4238105116584094 + -0.2146127374578656 + -0.2904641996440634 + 0.6841309250228275 + -0.1734036669822675 + 0.005484918036074342 + -0.3094351754069787 + 0.1344267232447092 + -0.6602876216385007 + -0.1758653406754312 + -0.3571123654793031 + 0.1814137431085418 + 0.9650432304737308 + -0.2398079143340615 + -0.1022114709403531 + 0.03833987493886366 + -0.3376619943855572 + 0.1669260746161754 + -0.3955724827984012 + -0.7739629842886803 + -0.0266264690360493 + -0.06371473601428168 + -0.3384160982798863 + -0.05691570711822313 + 0.07058341334237343 + -0.01760983935993179 + 0.2081866155072211 + 0.2984905798906045 + -0.2593394298702862 + 0.01981180292951551 + 0.4216274320393357 + 0.3486590169606297 + -0.07631088265866229 + -0.2152207410893138 + 0.1740728055653103 + 0.351290202185461 + 0.04066787938431084 + -0.7437385732488911 + 0.6547699883537691 + -0.8451054495912956 + 0.2292264008553798 + -0.0910354805579545 + 1.087828336259904 + -0.0444661460746549 + -0.1193586278922212 + 0.00836495372866819 + 0.4149317943238018 + -0.1581694414855725 + 0.08022494337025025 + 0.3714328091574364 + -0.2005283438516713 + -0.542568868853561 + -0.6382264845260477 + 0.2456136959769961 + -0.1647019171280566 + -0.1592900284421765 + 0.9506598247249513 + -0.1207854405852313 + -0.2320709254975472 + -0.6554658409277617 + -0.588265612204362 + -0.5559580747465549 + -0.4149467836913759 + -0.1721699893401752 + -0.09271062009813449 + -0.3065949565790526 + 0.3610463992147586 + -1.78045410986781 + -0.3813604075130993 + 0.2611315918154911 + -0.207841246725757 + 0.3654741734387875 + -0.3644560512267753 + -0.6258362695359259 + -0.0945642246204438 + -0.3941104951709534 + -0.06527453859664278 + -0.3584363686709794 + 0.4315938791984615 + -0.1953073467988072 + -0.2190909953692586 + -0.115021973890395 + 0.5799855764499777 + 0.4499280518089379 + -0.5754623080981474 + 0.531975657300825 + -0.4917340256474008 + 0.5072275379282593 + -0.7153225605620414 + 0.4846294110052394 + 0.5671459824889488 + 0.03992505321172374 + -0.6354848713516034 + -0.1867426422707893 + -0.4303902770886434 + 0.05275823539234827 + -0.4461769419672343 + -0.1229379590513772 + -0.4236142668132394 + 0.01106239915900415 + -0.02154850438347221 + -0.03911587016610428 + 0.9569181342427248 + -0.1128324858156322 + -0.1695409319828666 + -0.05347345920787545 + -0.1795049898251221 + 0.3169830183710285 + -0.3858293237770161 + 0.2037783992187152 + -0.2794130633306701 + -0.6069808533956208 + -0.5405563985527269 + -0.04436903747447773 + -0.05993332426826255 + -0.04974037829521032 + -0.1947166630766153 + -0.2516635983236469 + 0.3346425156244562 + -0.3918183728316629 + -0.4036485461565948 + 0.105743687571403 + -0.07132399658671379 + -0.5961395921676819 + 0.4239921022177991 + 0.05750311417620047 + -0.5471088188113188 + 0.1308358818651182 + -0.3976010903399521 + 0.1146153207182655 + -0.4476997987535604 + 0.01426975284128053 + 1.003570984477288 + 0.1452193440987051 + -0.4920617589968798 + -0.5690524190500713 + -0.2134868635891582 + -0.206170501706324 + -0.04551872261921921 + 0.8430678829372334 + -0.3573183298914445 + -0.05962991053493866 + -0.1001963259200308 + 0.2847204138826752 + -1.067253762044989 + -0.4326873724552786 + -0.7130954442931835 + -0.2365857079833269 + -0.5591639722162693 + 1.026305220224091 + -0.5373489300732801 + -0.1441161885568221 + 0.3954713930918267 + -0.2624003777474603 + -0.6800973467876378 + -0.3813540502920702 + 0.02821904743041741 + -0.3865876884501602 + -0.08912517604637459 + -0.4377488653601013 + 0.7829160956965705 + 0.5113482797258616 + -0.285247669325678 + -0.04442222555388487 + -0.5576208874960122 + -0.3505112609552292 + 0.1994045086736325 + 0.07125286146978603 + -0.2208518845142651 + -0.3202505459560078 + -0.1275974934391475 + -0.5368283548484399 + -0.1480910631784682 + -0.975609212789403 + 0.01524830790131133 + -0.3797981234106209 + -0.5498579688739406 + 0.5070616356581784 + -0.001014036535875534 + -0.2136852815281384 + 0.5351705137754126 + 0.08279981590377991 + -0.4575661231955304 + 0.5586819570966582 + 0.1739043109215139 + -0.1407498560001399 + 0.04272868334967283 + 0.2589469168022305 + -0.138637126227741 + 0.3913490250444416 + 0.06068764895200751 + 0.2879950589451611 + -0.1776425990110019 + -0.5470553498576566 + -0.03406831478065626 + -0.8856640480589015 + -0.3461303344982883 + -0.4023461757591711 + -0.5967203343406117 + -0.04762961620743728 + 0.1634154696283311 + 0.05156478889768506 + 0.374891437163266 + 0.2299621020330013 + 1.01764078070525 + -0.5542537884397342 + -0.7868807188082098 + -0.1262971870208869 + 0.05216108980434844 + -0.0722023109936355 + 0.2268641079788984 + 0.126409343375917 + 0.3224594870190853 + 0.5492181841314215 + -0.1329315953862936 + -0.7962834558222827 + -0.6022961242698679 + 0.4057523933407385 + -0.1588419956916801 + -0.1271202814589718 + 0.580341660931135 + -0.1631469874510582 + -0.2844734846955352 + 0.3520853860280144 + -0.4708253576023849 + -0.1477759737373208 + 0.2000449434284807 + 0.02390515810455116 + 0.8398425001088277 + -0.1637045561289333 + -0.05200944806289531 + -0.14638327980134 + 0.3766178616028983 + -0.5126500931342141 + -0.2669373765010273 + 0.02493733031875291 + -0.2934717180120997 + 0.824756983242672 + -0.5509116165875499 + -0.3916611609328474 + -0.3230987657043287 + -0.2514784111222529 + -0.1763128799012259 + -0.1933217809645003 + -0.37408932417309 + -0.1586106281388953 + 0.133115414169056 + -0.38928854969928 + -0.3592629507256938 + -0.3747091378581611 + 0.004420574358069006 + -0.6735642918324432 + 0.4881412103038595 + -0.06094400134750316 + -0.1633112102906608 + -0.734951957008667 + 0.306838462713064 + -0.2605132937858697 + -0.3404126612988638 + 0.3516440964860457 + -0.4766602216916284 + -0.05426675370681971 + -0.4342439540358475 + 0.0905079479202041 + -0.752640192074215 + -0.2411232653901751 + -0.5183463379948153 + 0.2126155799223657 + 0.948355905720532 + -0.251404012937978 + -0.01864565836884751 + -0.152745167675961 + -0.3721405280381076 + 0.007573265391428359 + -0.6043799101486504 + -0.8691910425416818 + -0.165923299089091 + -0.1757896034347677 + -0.3015416522430929 + -0.1333719889512778 + 0.04745289842002288 + -0.222624961467681 + -0.1631402378169525 + 0.0739691720732934 + -0.1689965018755382 + 0.005539011694333889 + 0.6129557359718374 + -0.4440599719271117 + -0.3418145940577555 + -0.293785222543304 + 0.6078366804029476 + 0.1906107547366269 + 0.137547076884127 + -0.943828539188439 + 0.7542068635643424 + -1.015740738824357 + -0.2226812806909455 + 0.09622791925686651 + 0.6386974647154608 + -0.1553697927018379 + -0.2751948666931138 + -0.1178172406670678 + 0.1506741517475596 + -0.2192374339679856 + 0.0135607250263139 + -0.004752347692954299 + 0.005054603630500858 + -0.4789227097538492 + -0.3271859252645017 + -0.1580288546184008 + -0.08159157907690892 + -0.2166292514303432 + 0.5961321612150892 + 0.3707747287391505 + -0.2595670498573999 + -0.5778442850297116 + -0.6142482455949375 + -0.7786208651206313 + -0.5311628869128089 + -0.2070242437373837 + 0.2423429217005519 + -0.09245807969026332 + 0.02615242705254926 + 1.942214456604149 + 0.07208652198382035 + 0.1504526940669746 + -0.05671761665546045 + -0.06677154272410081 + -0.5413677077846294 + -0.6400015435233035 + -0.7474244708216383 + -0.5783654785183465 + 0.08554097884892409 + -0.3741144811529576 + 0.2892656903887446 + -0.1525561886731615 + -0.3020201241191387 + -0.1405210702236058 + -0.2410430005772214 + -0.124156588480938 + -0.4829678766533977 + 0.7552798920589129 + -0.5025719260091526 + 0.04839544960622997 + -0.7348360949421585 + 0.4634060934266534 + 0.1885051703879014 + -0.3369733760555384 + -0.6455485059546264 + -0.1281979342578744 + -0.4972877106215881 + -0.2173002860186208 + -0.4275808205441188 + -0.08610192215690848 + -0.4741005227561371 + 0.05390825452802709 + 0.02131214188614609 + -0.03694598086610448 + 0.4851014317380515 + -0.3749988873268422 + -0.2153080505518481 + 0.005454571033644709 + -0.06216789174860946 + -0.05298547864825581 + -0.3776317477238814 + -0.2033939365053905 + -0.2729618944782381 + -0.617892763468474 + -0.5639878821042957 + -0.300527489898864 + -0.6502440469005009 + -0.1661282163318294 + -0.1854846483129881 + -0.006825468443105815 + -0.1454399028385248 + -0.3735116269659869 + -0.5043072482481197 + -0.09373620565476463 + -0.3468495424275193 + -0.4970941831883467 + -0.1946564746342996 + -0.0128130086532128 + -0.5956489362061527 + 0.2880632110527631 + -0.339743804629175 + 0.2302477552400708 + -0.5155223897531509 + 0.3230057499453503 + 0.2443372096977281 + 0.1857369124026829 + -0.5216692991239195 + -0.5302076887443022 + -0.3336553073704617 + -0.1643661678253931 + 0.03181972875602657 + 0.5721384201397109 + -0.4072878610131206 + -0.06375422981163069 + -0.0662786403733346 + 0.3134737792595582 + -1.084549023715948 + -0.5955791155606697 + -0.8054529387630414 + -0.1051827144574285 + -0.6791187379527408 + 0.6462816413821661 + -0.5280350810192099 + -0.1648132542036891 + 0.526712757951232 + -0.09628546759534155 + -0.788958909796334 + -0.4110895253730163 + 0.02938766500826371 + -0.3816012990976516 + -0.2855459266116003 + -0.3498999592906448 + 0.7197165137063136 + 0.525578745117918 + -0.4399810046534121 + -0.1176780637657514 + -0.6574389741286525 + -0.4059997477136861 + -0.02724444073919859 + -0.2410073835946322 + -0.2825317206242124 + -0.2876586024759145 + -0.1298022304206394 + -0.2049024513723418 + -0.8038773122221586 + -0.9975979347616613 + -0.03281499261344051 + -0.1940293767501099 + -0.7860682768196964 + 0.4543715285779033 + -0.07209027658748152 + -0.1446449097416507 + -0.1868152497898727 + -0.5881902819879754 + -0.5321495288436316 + 0.6425934220835628 + 0.05838196677647711 + -0.06241466981931418 + -0.2258698606250561 + 0.1637755188302492 + -0.1268876669791284 + 0.06679710616576874 + -0.1745458432677706 + -0.4748157857742784 + -0.3874042266589584 + -0.4659903196160114 + 0.172659502462631 + -0.9203095010657294 + -0.4016074524432053 + -0.2846290115047411 + -0.688387086349787 + 0.09400168903740208 + 0.482718361588352 + 0.1907900932278317 + 0.6582303876744932 + 0.367157062330624 + 0.2690321364338947 + -0.5779947927492164 + -0.7309560554516883 + -0.128657432304649 + -0.09187162706370723 + -0.1882842217449678 + 0.40874401973777 + -0.03130755302113058 + -0.3412385797966293 + 0.234304443341925 + -0.2454741056646836 + -0.8174339501665628 + -0.4409480491605677 + -0.003423790669959458 + 0.03471918611582803 + -0.1751602049742589 + -0.0962699260609152 + -0.3575486518148243 + -0.2997772098928483 + 0.5528427675133079 + -0.4121011613286376 + 0.04238504407094401 + 0.2405879512685 + -0.1012576708106302 + 0.2279585778625073 + -0.2863998298406531 + -0.05219271166546807 + -0.305340545950068 + -0.1902978854849447 + -0.523803810243433 + -0.3461196904921145 + 0.05097977700431616 + -0.3051033284103351 + 0.1209534532016621 + -0.3118662592391754 + -0.2471677289165367 + -0.3125483853830653 + -0.3104062832576036 + -0.4092539943953493 + -0.241651308123654 + -0.379341148361141 + -0.2501425531983235 + -0.2518264578417332 + -0.3966071359905799 + -0.3240074369953281 + -0.5662052753132578 + -0.2093338097701624 + -0.3654291491401669 + 0.618226872646975 + 0.01197486512055113 + -0.3029674445530482 + -0.6831754900066797 + -0.2282876800713723 + -0.1867473527777132 + -0.1807807287112149 + 0.01182529324308042 + -0.5783718429461576 + -0.05890433736285863 + -0.4596359838036555 + 0.06885394425402475 + -0.6632254849218142 + -0.1119292966104332 + -0.3877424738160345 + 0.2503909100523899 + 0.1635842514715485 + -0.3359498325708253 + -0.1415028506256285 + -0.283024730305682 + -0.3154435107845465 + 0.1277001905978781 + -0.6027792371346498 + -0.8613851761163197 + -0.1716816907748511 + -0.02833239581533218 + 0.02422305156303762 + -0.228209148920771 + -0.07642839357270599 + -0.3370520799134479 + -0.5885763840417114 + 0.1216933565689515 + -0.08781274217183209 + 0.0678691506744504 + 0.8424386819484797 + 0.1373254746392774 + -0.01848687134635017 + -0.2380789556814966 + 0.3417536574220434 + 0.4341107023035369 + 0.3841811126078573 + -0.8935118834612313 + 0.01571764673947633 + -1.042059171744363 + -0.8365385347930292 + 0.3401309333656257 + -0.2915878882651581 + 0.1051927749202422 + -0.2901577020926721 + 0.0618613740823458 + 0.1533367066468448 + -0.2252632609392385 + -0.0003889279360040632 + -0.574137609203859 + 0.1966132976521402 + -0.4753077034071311 + -0.3572521744406706 + -0.7600784837680594 + 0.1047355703523071 + -0.2638850591568736 + 0.4206406658170802 + 0.7805677897879814 + -0.3590121499116142 + -0.6126076017729987 + -0.3302466011684718 + -0.8327453653806592 + -0.2046762646182836 + -0.2275626429313998 + 0.2320441691743063 + 0.1401799332325747 + -0.5970465754508761 + -1.780599153696266 + 0.07756987606041904 + -0.3081400852234309 + -0.4248968471027421 + -0.2693592531484564 + -0.5683078211876698 + -0.5945883095431329 + -0.8705911103661095 + -0.5075128735422443 + 0.4214597634040959 + -0.2486203285499218 + 0.1125025700369858 + 0.225057411613186 + -0.1430888696058143 + -0.1429968851306541 + -0.5604979110577604 + -0.5351480260750218 + 0.004678630466235922 + 0.4320858695144522 + -0.5161319662964049 + -0.3630488095515725 + -0.4527927889180065 + 0.2031393281035178 + -0.1607454270140085 + -0.4966602900840969 + -0.6582776894049744 + -0.04318015066022519 + -0.3635098083101613 + -0.471579012273411 + -0.1123145540876857 + 0.05589509485996638 + -0.4836089243064695 + -0.06424757629741631 + 0.3175334511103713 + 0.06938305935798574 + -0.3293119100959557 + -0.6367383000612401 + -0.2040734804354499 + 0.04266999162404084 + -0.04060325871850645 + -0.3757511228832247 + -0.3815103374201938 + 0.05287483712614335 + -0.09858223122449138 + -0.5837487434671705 + -0.4299966143237329 + -0.2148995151424994 + -0.8285804665265564 + -0.4165323504967136 + -0.1857809070418956 + 0.3446712216799147 + -0.4880118815776988 + -0.1894365459451416 + -0.4380478611667041 + -0.0763717173429115 + -0.4952954920935713 + -0.5693328535465947 + -0.4754685200172154 + -0.1007641264668812 + -0.3800576287270971 + 0.284635942408415 + -0.2709478490104187 + 0.2334849156425411 + -0.5605803775049333 + 0.3945194182158658 + -0.3357561736624433 + 0.2253190472079402 + -0.479571204852919 + -0.5695138081165433 + -0.3906093647055345 + -0.1365679338739176 + 0.05764066780159962 + 0.08603301501314856 + -0.2196888087093433 + -0.1234972996007928 + -0.0986833872951893 + 0.3237792379812792 + -0.8613525024878457 + -0.5615509348870983 + -0.7592446921472276 + 0.1699980362800157 + -0.4653118715861744 + -0.2158006747055174 + -0.2500944346872818 + -0.1287854137025125 + 0.128934571740776 + -0.003526488785242154 + -0.8399276712505523 + -0.330399341517634 + -0.01560115462140701 + -0.352187401170877 + -0.2560230975307909 + -0.1958792003549243 + 0.01514683254785584 + 0.1089498658005297 + -0.5585856462889451 + 0.1480583418170258 + -0.6789117454684233 + -0.3929536172126375 + 0.2071827027731075 + -0.3573211252942662 + -0.2629996235435352 + 0.001391320378811444 + -0.1169842512237953 + 0.1198736272528314 + -0.737587748318728 + -0.9270430400979962 + -0.3577244664949029 + 0.1776867345474032 + -0.6732144224554912 + 0.08819573140103359 + -0.06922081909004965 + -0.1024104914371722 + -0.6596795250648703 + -0.8987836492684684 + -0.6217412233252386 + 0.5988427651116034 + 0.1024886468185866 + 0.2814267734258853 + -0.440849302190123 + 0.2833800216072526 + -0.1857008106833104 + -0.4790854306347693 + -0.1410378587265264 + -0.8097925772780029 + -0.4025154663769632 + -0.5350615369579589 + 0.09176713893577661 + -0.7769137755094272 + -0.4436049473708966 + 0.2343623787993738 + -0.5701056042917206 + -0.01064426636932409 + 0.2954508823005327 + 0.2358216485226806 + 0.2181170324298531 + 0.3495023267527235 + -0.2927560280883714 + -0.4162973994033312 + -0.5906676988840915 + -0.1222333382354282 + 0.08664743597606636 + -0.2651065135750781 + 0.08935692622538703 + 0.1381891885489051 + -0.3560236805655786 + -0.3290535692413685 + -0.2352849906006602 + -0.5946768609244922 + -0.06981201403965386 + -0.1493741410658145 + 0.5328681676798306 + -0.1803987177453212 + -0.4656443892726355 + -0.2449153482117758 + -0.2656246175033493 + 0.4126557393360887 + -0.06970205768609888 + 0.1689991496794057 + 0.03521543088269639 + -0.1734343633323954 + -0.2564711009803666 + -0.1574609723597054 + 0.002429636388936149 + -0.3187242454451427 + -0.4410757545849738 + -0.2359101417730298 + -0.3100384590225302 + 0.03471939488113072 + -0.3296317688323425 + -0.5098149823851663 + 0.1115913721329731 + 0.05544012386448133 + -0.2966993802900029 + -0.1209047751876421 + -0.3866592490685754 + -0.1826766095340182 + -0.4171484883108832 + -0.2055397286381209 + -0.7338480244931559 + -0.283080680774467 + -0.2987096942708872 + -0.7017857700949461 + -0.250202168055706 + 0.08381076909182114 + 0.332480902185142 + -0.4351887355398816 + -0.3163994729811774 + -0.4724570727667632 + -0.4884225332146895 + -0.4150732055937091 + 0.07797318041408605 + -0.03151408728005083 + -0.6058452367039552 + -0.07677053496821562 + -0.1392373581209522 + 0.0006927963515423502 + -0.656714391695566 + 0.2670241507563403 + -0.2274640211730099 + 0.1341297488331412 + -0.3458294865065677 + -0.2721745884432445 + -0.1487729025880484 + -0.4218555509077397 + -0.2251641955182626 + 0.458214894576395 + -0.3824456598159615 + -0.6264304719445675 + -0.02818429183189752 + 0.2873914589498447 + -0.2338890229101601 + -0.4467807308459597 + -0.135648058213299 + -0.200936807542687 + -0.7314371257828245 + -0.449482767223645 + -0.1042173793885466 + -0.09641920731737179 + 0.6206538973634722 + -0.4435485103285841 + -0.003479203257694294 + -0.05194601433788879 + -0.1700149283501921 + 0.5020815222136729 + 0.0192417018483452 + -0.6057225242512514 + -0.2621997899297607 + -0.8682309385078543 + -1.043226215785034 + 0.5722085366169893 + -0.4789889334996213 + 0.4311134707884468 + -0.101731891758905 + 0.2487426248174195 + 0.01732784564969043 + -0.3846973076070464 + 0.06265948837716913 + -0.7293727917649786 + 0.3199024793730494 + -0.2831940560390996 + -0.198043463486127 + -0.9064857416764353 + 0.3022793558404221 + -0.3038014268564736 + 0.02765174351442887 + 0.7054582590677552 + -0.4053038671205914 + -0.5922230756584481 + 0.0907887262006568 + -0.7964267323984823 + 0.3489800291146762 + -0.1950297082350069 + -0.1181827315175544 + -0.04118604247545288 + -0.6400703568846832 + 1.590408800181046 + 0.1571280168753901 + -0.4780752919448401 + -0.6494939895635206 + -0.05350493158024193 + -0.329179308140593 + -0.257915126993325 + -0.8452967617689512 + -0.1919436667441916 + 0.08452274833016174 + -0.1506276388393554 + 0.01064368205982586 + 0.378029109083333 + -0.002957610086980191 + -0.1433967042786035 + -0.6681496213324567 + -0.6965558583695808 + 0.07571463971795134 + 0.02660778153957135 + -0.4866147033920999 + -0.4676101780756626 + -0.09402517136169601 + -0.1326465655751625 + -0.2803161262685953 + -0.485866789551306 + -0.6445031845162837 + -0.06321898795230017 + -0.1374206965699841 + -0.4298840398853365 + 0.3437860129195507 + 0.1592555937562658 + -0.2693761470584372 + -0.1425018237827043 + 0.3288224426709815 + 0.0195566626478075 + -0.654391449308484 + -0.6664374747216034 + -0.3510986932119884 + 0.03509224374305035 + -0.147292553679547 + -0.7057787800957498 + -0.4426942656955598 + 0.01710547508556669 + 0.3133941036713175 + -0.06798168256159805 + -0.07650107513124035 + -0.1655639353152909 + -0.9519765174331033 + -0.3779128940251456 + -0.2298855679561967 + 0.2021331965923949 + -0.4780967027784193 + -0.09950319619920876 + -0.4720304411565514 + -0.1112782900500317 + -0.3773567266591552 + -0.5667222274309959 + -0.5896218913169158 + -0.1510458944758229 + -0.04156115793996827 + -0.03681408002395202 + -0.4049332155526779 + -0.02564108070178676 + -0.6269657015590318 + -0.01375084422072832 + -0.7141367265552291 + 0.006402219572510645 + -0.1116813095085798 + -0.6351424844998569 + -0.3215358210264493 + -0.1453723291787659 + 0.05600993134507122 + 0.03509606520352065 + -0.2278840841918018 + -0.09522467680281629 + -0.228585377418122 + 0.08195281332895714 + -0.1842305797350325 + -0.4984737766499143 + -0.4774309346289708 + -0.008274983605111122 + -0.2823742909616017 + -0.5074415497056384 + -0.0601794615320619 + -0.07871156883960556 + -0.00377493693413423 + -0.09820926355559258 + -0.7688777294662257 + -0.1374337098313828 + -0.06543259074014873 + 0.02158491328776586 + 0.1396910922816859 + -0.2860301223920511 + -0.3672166937853523 + -0.2510587610670307 + -0.7060334798031539 + 0.2515814693383551 + -0.6614633043811741 + -0.2949217675439889 + 0.4303324168282956 + -0.3135406019711567 + -0.1993587358280154 + 0.06932898965958072 + 0.02217375067049907 + 0.3213100649691303 + -0.4335256262750316 + -0.4281642139585038 + -0.473963183933536 + 0.2133249927104609 + -0.4004653724469927 + -0.151378714167807 + -0.02945951951758842 + -0.142659286076651 + -0.7121306953654724 + -0.8445663015726538 + -0.2209021606614747 + 0.512200415597961 + 0.13769296313119 + 0.5519345468118018 + -0.5762499488813367 + 0.3555599434085788 + -0.305311940074022 + -0.6351470680682418 + -0.04196554042601083 + -0.8998594993504928 + -0.4535528189901826 + -0.6777603265344038 + -0.2887483673233799 + -0.2831278318562285 + -0.4127703587845231 + 0.4146056042245125 + -0.3064887161727025 + -0.1141271356089437 + -0.07834559455024592 + 0.1277111151789827 + -0.4689873231334128 + 0.2541968472283095 + -0.4181961051962566 + -0.453338303251671 + -0.497127561623368 + -0.1288193178658342 + 0.09946804927215061 + -0.12091369625438 + -0.396217561134134 + 0.3894409469451128 + -0.4567492349068292 + -0.4467548413341039 + -0.2729206784507691 + -0.3992577023411391 + -0.2573050411317117 + -0.2067353367913678 + 0.5553610595412475 + 0.04538662696329159 + -0.3803851835258086 + -0.00259323383371598 + -0.2350047786824387 + -0.1829308873898255 + 0.5419626222596291 + -0.03811420635925365 + -0.185960744657928 + -0.2164678225760939 + -0.4200307266349941 + 0.0002546722747690633 + -0.07481360739756698 + -0.1625080928643031 + -0.4125995043730831 + 0.1502347487002705 + -0.1108577175964447 + 0.03345724174870192 + -0.2647308458052282 + -0.584897453222202 + -0.2650084377370297 + 0.3530167565089282 + -0.1902048302092513 + 0.1541529182310633 + -0.1538034588366328 + -0.08610237613014243 + -0.4160826091813778 + -0.09220729602744239 + -0.8254781753596087 + -0.1683985710011476 + -0.1735331419808584 + -0.7272198112431602 + -0.2717276480951551 + -0.2211317713624017 + 0.05543300345384761 + -0.6889324090807434 + -0.1535171750177869 + -0.1836087058263277 + -0.3632190296038028 + -0.4846933554914004 + 0.2302330350816434 + -0.102657421229265 + -0.5803153691199542 + -0.04487682653247512 + 0.2462586672395643 + -0.01417572099124056 + -0.418053859829126 + 0.2724431659469464 + -0.4492959915335534 + 0.05943425868649164 + -0.5366000624281262 + 0.06590299731818172 + -0.1273034477604761 + -0.3070846767492227 + -0.197093048201637 + 0.7219881824524234 + -0.155631745676243 + -0.04563653298760457 + 0.09480141906801526 + 0.3893130988045581 + -0.4143033631645172 + -0.5812985885040769 + -0.1412033826050553 + -0.1309092407210991 + -0.7567019244018102 + -0.653214702445443 + -0.1231280865165363 + -0.1867860070024334 + 0.4687074101654123 + -0.07346352365363995 + -0.4513008291317256 + 0.1414997796645397 + -0.3930457399982226 + 0.1631704198669574 + -0.4001551301711788 + 0.01042299058816831 + -0.4046580574017991 + -0.2040063920270557 + -1.102677030407465 + 0.3518882150110856 + -0.6382891836101693 + 0.3346394949630933 + 0.3602337672832703 + -0.05594881120170617 + -0.1656607059035895 + -0.5210339696533037 + 0.1185495276223964 + -0.340517133351099 + 0.1902629384864901 + 0.1621509275941509 + -0.71835646970261 + -0.8127341619973234 + 0.4469372558920139 + -0.3512253696851279 + -0.457648781991237 + 0.3527961760445964 + -0.4035043205011868 + -0.1225143340455787 + 0.4983127024531727 + -0.7183171201401464 + 0.1876845817269912 + -0.2093057835543573 + -0.2019724687188628 + -0.1713789561376335 + -0.3952918491817058 + -1.780978883369023 + 0.2054842071086569 + -0.4635030503835605 + -0.2956284372493603 + -0.001774898250552024 + 0.1488280602474648 + 0.1264226549129192 + -0.8286877440999377 + 0.2245515245693221 + -0.3073731151894248 + -0.06460709917175121 + -0.07790419215112504 + 0.007877119553052977 + -0.09092231242175547 + -0.1686780185257491 + -0.765013763816823 + -0.6871377717234923 + -0.006594425772513775 + -0.04806563673352361 + -0.3037413570737171 + -0.4753764674771662 + -0.0379924271185581 + -0.2571618251627662 + -0.2459781214801 + -0.4163424599886744 + -0.4175941733527985 + 0.01312125107172365 + -0.02035363517690484 + -0.02847920176124768 + 0.5206458942302443 + 0.1079314780400711 + 0.0009521103246746602 + -0.1253918872207877 + -0.1693561910156049 + -0.1016467216058956 + -0.8184227805599097 + -0.7299448618632853 + -0.3707293502550358 + 0.001252315368334842 + -0.3326712945128822 + -0.5176513739044207 + -0.4375717545721807 + -0.5399760187668166 + 0.2186112767831467 + 0.5257085521262155 + -0.135808682835768 + 0.0579250191708186 + -0.5360367459179185 + -0.2452683086022597 + -0.2616003825821842 + 0.05008352235535284 + -0.1258846733544287 + -0.1190667804258561 + -0.660169922962523 + -0.1080773298518675 + -0.001930059900269921 + -0.2254690900251465 + -0.5199738071019793 + -0.15368605110091 + 0.382747030021245 + -0.3399709960143961 + -0.05185000718016074 + -0.1809122102596091 + -0.3344644883054311 + -0.1577847536637051 + -0.5534016355907267 + -0.1609953751694373 + 0.4180245105874469 + -0.7122580027821085 + 0.005350136450229161 + -0.2130573081651347 + 0.0547486758571803 + -0.09144499173330059 + -0.5043758693566643 + -0.08137944512578063 + -0.165721680075962 + -0.2147303372558582 + 0.1802639287302827 + -0.2503409246424228 + 0.008387856501332013 + -0.1343322075075337 + -0.1552770470090488 + -0.4236960286618235 + -0.1051338219795501 + -0.07967984352968752 + 0.06485908420979801 + 0.01619844664292754 + -0.6022687374535013 + -0.1064542089149937 + -0.1135033618750938 + 0.3748822295642341 + 0.3055917998483587 + -0.3332077235466904 + -0.5053144394121257 + -0.4181511486753801 + -0.5480040773026975 + -0.1093613562713298 + -0.5535666429787212 + -0.1495924073026777 + 0.3717905496599088 + -0.07874312291855366 + 0.0197351116593076 + -0.1857099985425998 + -0.04408574975722964 + 0.6265704341874341 + 0.0411248751029252 + 0.2177664529664201 + -0.463326466177071 + -0.1155788520119949 + 0.07627480780988947 + -0.1154392196611928 + -0.05354405147501572 + -0.09449540109562496 + -0.5771323721290285 + -0.5184918414810038 + 0.302546362799287 + 0.0418575769084128 + 0.134369023143456 + 0.272872593738047 + -0.451072112669163 + 0.2222601662559372 + -0.3671819292660506 + -0.6668562782762132 + 0.1268313211719089 + -0.8644601868357874 + -0.2605807864844837 + -0.6512543457612744 + -0.2815701835236822 + 0.03980362031234853 + -0.3384463768631267 + 0.1358336920104301 + 0.1764416948239552 + 0.07118155278932202 + -0.2955362599328757 + -0.0620030852375667 + -0.5535991388553626 + 0.2081219248241339 + -0.1849028896935379 + -0.730857270559144 + -0.06876572091017155 + -0.130106666752676 + 0.261837008192287 + -0.1167673382119821 + -0.3435751842616931 + 0.2185022598636893 + -0.2986719176606851 + -0.3476349706604125 + -0.3383069171226881 + -0.4943657876494036 + -0.3014395244202314 + -0.1512277644792329 + 0.2497477773393427 + 0.3684965157080135 + -0.03975557072904728 + 0.1156069179951857 + -0.07180650093159041 + -0.2438028687998155 + 0.4418684913637954 + -0.1536875051000218 + -0.05110101265443797 + 0.04262054514314754 + -0.5450020522064242 + 0.06382102010754576 + -0.2633338422159232 + 0.03428998973366581 + -0.3396396278171734 + 0.2218785662937951 + -0.1406035549058024 + 0.009704001788654788 + -0.2790755487712052 + -0.3025930785630245 + -0.5992507698826174 + 0.3179612276310023 + 0.003149844452743701 + -0.01660386451206627 + -0.03989765752844681 + -0.1471733429454518 + -0.3991178639965604 + -0.2310807981650578 + -0.6165195989948826 + -0.2443863922497242 + 0.1446641504619525 + -0.7581687113193498 + -0.1630934639146746 + -0.1864094203189325 + 0.007390622514341341 + -0.4222623583706733 + 0.06589276325146391 + 0.3931121254033183 + -0.05997993820942499 + -0.6096833499924588 + 0.2736455897344224 + -0.1761486303371735 + -0.5060751065354971 + -0.02909222922175481 + -0.01524255743558093 + -0.1839560200807636 + 0.04091625043667953 + 0.1315026676092598 + -0.4866903458965861 + 0.1711047202539764 + -0.4422489010456397 + 0.001511426167088095 + -0.04639869365802123 + -0.07198601017677353 + 0.01831033130226101 + 0.5726396179628991 + 0.1963252025856242 + 0.09560035596270883 + -0.07479006174482507 + 0.2383236076594711 + -0.6525137457339615 + -0.5733500639054371 + -0.09277279640447748 + 0.2135053197475681 + -0.5839706148374094 + -0.5772042349178457 + -0.02587418833276165 + -0.1758147521967876 + -0.02039002839069973 + -0.4584890671511103 + -0.3727776208085981 + 0.2161430387505507 + -0.33382871875445 + -0.1018758948934526 + -0.5155807499245789 + 0.2230774657853115 + -0.3842771617731814 + 0.2765709669076771 + -1.11437088776058 + 0.1370290419361331 + -0.6907121556971 + -0.04739560124816106 + 0.4945854676725926 + -0.2518511238092139 + -0.2090823881211713 + -0.5826711045003965 + 0.04548258606789699 + -0.1853294453073051 + 0.1542278754398604 + 0.4641990825116425 + -0.3355069922025304 + -0.3325706576622386 + 0.240999893509847 + -0.3739549587971491 + -0.7292391624211603 + -0.1778788290675548 + -0.32985631835857 + 0.1773685507675661 + 0.3143987682501025 + -0.4241186269008492 + -0.1196109874348598 + -0.2703331487635954 + 0.0646029191795594 + -0.09293151587895067 + 0.05867323189292146 + 1.572152959310365 + 0.0270851943823703 + -0.3201605719329901 + 0.03511290922165978 + 0.1842220640356778 + 0.4459288682235256 + 0.2279510038651417 + -0.6208225668217512 + 0.2033200440448049 + -0.4768920295949141 + 0.05635444804434454 + -0.1792207056397316 + -0.05082725323384989 + -0.116466160497955 + -0.1646789310506677 + -0.8546516345710713 + -0.6863333032159274 + 0.1251280715920445 + -0.1954916256772424 + -0.06330408849680744 + -0.3614178746908751 + 0.1110444058475385 + -0.4441635474921972 + 0.0421501215297819 + -0.3563461749842403 + -0.2847085013375505 + -0.01885466908589918 + -0.08714902937426544 + 0.1108528108141068 + 0.1868153364508421 + -0.0782948091852478 + -0.09368056609716874 + -0.06796896435348695 + -0.497680262528085 + -0.1496864352033443 + -0.7899711281536115 + -0.6025616651729295 + -0.3411802195266797 + -0.04670556170928879 + -0.3428166896726749 + -0.2845726199256554 + -0.4125870758047719 + -0.3383725144380084 + 0.04576291584876581 + 0.4867574895058831 + -0.1734111351515317 + 0.4046916923000636 + -0.0692196393810556 + -0.364205893770604 + -0.2551900009272337 + 0.05737247351539661 + 0.08039984007240546 + -0.11299788125515 + -0.4721938914488412 + 0.04841770947422069 + 0.2143597286200945 + 0.1183004551578102 + -0.363460031717068 + -0.1907615130706292 + 0.4028808348822922 + -0.3171712423084697 + 0.1974988994089932 + -0.242326408426382 + 0.06990657685043837 + 0.03283291026075733 + -0.4808273426038372 + -0.353546190225623 + 0.3814243035574654 + -0.6407503423680718 + 0.3096372846159585 + -0.2214550425447073 + -0.02287760645039265 + -0.1304712309055208 + -0.5079350855894919 + -0.09170209542267782 + -0.2564185760653225 + -0.4122184566482636 + 0.05779244757900356 + 0.1355589819676707 + 0.3286801707679867 + -0.2242603117821102 + 0.0335455361107912 + -0.5371454248562983 + 0.1317342409872321 + -0.08379994681574615 + -0.1375314996449098 + 0.1556617156194927 + -0.2608544997717424 + -0.2488335162112193 + -0.1214693826932154 + 0.1554129338795171 + -0.005680118626726197 + -0.1059142855277008 + -0.6238782668523944 + -0.5963151157794544 + -0.2148362270843856 + -0.3258183472222976 + -0.248606488482252 + -0.09849441598768362 + 0.1805113569718476 + -0.04418818805519761 + 0.3737371718874873 + -0.1530315749338608 + -0.2235354786574718 + 0.7630667232166822 + 0.2642022185562009 + 0.3208451718589377 + -0.4680450945273534 + -0.171291712100384 + 0.1519325249856672 + 0.0864344929490222 + -0.1192515192935129 + -0.05985311789830235 + -0.2929187491434199 + -0.3373089593719307 + 0.2738443816818401 + -0.4459312647860724 + 0.1019232205332759 + 0.0505340192312996 + -0.2868115385288292 + -0.1693873008287598 + -0.2983439658193252 + -0.5193256213739745 + 0.2007825339743431 + -0.677732951503412 + -0.09657284972081065 + -0.4774623379542781 + -0.01895688026804819 + 0.1338266916968649 + -0.1412708513186414 + 0.138190548765444 + 0.07912287981106435 + 0.1137545407236712 + -0.2905926167465767 + -0.1433534307405324 + -0.5789718450772364 + 0.06703335477883755 + -0.2909611390633863 + -0.4768384780853501 + 0.3468340324384735 + -0.1242840480300472 + 0.1628599665526195 + -0.2098058380705283 + -0.2650524620418804 + -0.04530575041494886 + 0.0742239161679762 + -0.2315164120681402 + -0.3974653743649324 + -0.3949615742671702 + 0.1431491502245915 + -0.06100188175408954 + 0.254619509251988 + 0.2385636964554492 + -0.0377979983973895 + -0.08510487825699684 + 0.07898195343477653 + -0.3157876622138711 + 0.3101460860926867 + -0.2513762463139826 + 0.02130796450574071 + 0.2262271679854062 + -0.5401435669147285 + -0.3928044928834363 + -0.2627404691172375 + 0.1127320496462008 + -0.3874823969145912 + 0.01510115021532389 + -0.2242313304610447 + -0.03784015856384065 + -0.231376614555029 + -0.08660512547898351 + -0.2163715339732224 + 0.2014987297473436 + 0.00183042504023886 + -0.3018592518870045 + -0.1481235804195503 + -0.1354999653037391 + -0.09485588183453179 + -0.3306772971591763 + -0.1183932030843847 + -0.2962642578543512 + 0.3651718826337273 + -0.3648497928756702 + -0.02235452262494591 + 0.281071647808349 + 0.1376248104624031 + 0.04071968038686895 + -0.0623331878745489 + 0.5235593914018143 + 0.1847146953260254 + -0.5898320982543569 + 0.07259131492753236 + -0.07542503649687438 + -0.3877343858715561 + -0.07180098022627282 + -0.2175881717960334 + -0.261557164031689 + 0.2491196222479528 + 0.04101563216656046 + -0.2394441282095503 + 0.2637079765764338 + -0.491673551927533 + -0.3199563992575 + 0.2237069053073689 + -0.1916615770179255 + 0.03207752718399837 + 0.1150203537322834 + 0.2999929701318548 + 0.1594169188046992 + -0.2518452325433932 + 0.1315469323585451 + -0.5568227828411216 + -0.4552940231107597 + -0.1225571536787343 + 0.3087794611803037 + -0.4073169324749234 + -0.4018687778918577 + 0.1001182006973928 + -0.1233661035052116 + -0.5311694950430884 + -0.06244269889225383 + -0.04191660189537352 + 0.1652929995941863 + -0.2685189742071611 + -0.2022708955035912 + -0.4994199663615731 + 0.2949704313847821 + -0.0413959778685745 + 0.1839277872468872 + -0.8877791188039712 + 0.124646207202205 + -0.5174491059310083 + -0.1741877905242727 + 0.2182184736194161 + -0.1985385581553671 + -0.1495612649704648 + -0.5022711929891177 + -0.03208153325427857 + -0.3229429888774093 + 0.1232233055373354 + 0.2090266598930229 + -0.565694282351267 + 0.004313344182687162 + -0.0508010608429796 + -0.3660963789208949 + -0.7893390105930082 + -0.6141821686914091 + -0.1735863843034059 + 0.153064126764466 + 0.2688441272796904 + 0.01891955490740877 + -0.03993908158052884 + -0.2345909675961855 + 0.0488287063273122 + -0.1771437205453895 + 0.07067450063965428 + -1.781448255057624 + 0.08491388308960003 + -0.03810905788179736 + -0.3085800186030186 + 0.1155403599852064 + 0.3749475045315057 + 0.1361256280495673 + -0.381924303711864 + -0.0602324042427213 + -0.4588384239011747 + 0.2167459982336198 + -0.3119731657244059 + 0.09338490336141297 + -0.00013580052025487 + -0.1582682259768826 + -0.8192320269381829 + -0.5635562527794323 + -0.1163258468853171 + -0.1849412934159787 + 0.2078265387141373 + -0.1693054398482254 + -0.1339753540407564 + -0.5926870633174385 + -0.2068659662318922 + -0.4028693742414952 + -0.1592433573791794 + -0.03298466862338994 + -0.2664711180239981 + -0.6223670831098527 + 0.2539463342474416 + -0.2112463899073392 + -0.06707021797068523 + -0.2540933845523378 + -0.5723527575894582 + -0.2663211757105155 + -0.559775271923221 + -0.1669748156094223 + -0.3391612146520647 + -0.007304739959241142 + -0.3714503942196212 + 0.1978289085127442 + -0.2994606800321042 + 0.07648124144600604 + 0.1120042552350718 + 0.2106307826577676 + 0.001842787583032354 + 0.3002279075694899 + -0.1444902776971541 + -0.5616957465792392 + -0.1711839811946715 + -0.1908787083942699 + -0.01413513841741283 + 0.01441352600904396 + -0.2493234142352183 + 0.07187192025363083 + 0.08250887000827953 + 0.4622517571621938 + -0.3484961403360574 + -0.2500344340875087 + 0.327055980519856 + 0.01861793533271652 + 0.1246782192478675 + -0.3286139189108901 + 0.3619715668980983 + 0.2289805073568801 + -0.7468191925568648 + -0.5389303871852547 + 0.14594117923781 + -0.4542946657875223 + 0.2432635170910493 + -0.2263087899597126 + -0.04143624459168473 + -0.2929049223777545 + -0.4249351946087646 + -0.1945125584822932 + -0.2787407752932843 + -0.3020247629591156 + 0.2550596994518242 + 0.1787026603248639 + 0.07429499669250805 + -0.1636903109796274 + 0.2187793428277464 + -0.6477365560999034 + 0.121753783403594 + -0.1053863531423386 + -0.439961013599136 + 0.07622327403616731 + -0.08556302169099331 + -0.0008746784338009017 + -0.1351544972756517 + 0.1271525507074459 + -0.2176602092416781 + -0.01554345296761483 + -0.5222439855642136 + -0.7316171375860131 + 0.2446548485233575 + -0.1467291582369216 + 0.1175902634457195 + -0.1681546882107498 + -0.04521157099650252 + -0.2043091023341305 + 0.4424845033373849 + -0.02996202084625425 + -0.4227659748562899 + 0.5910684140400475 + 0.1593138334345164 + 0.3361204425311022 + -0.1920805023816655 + 0.09822228634348028 + 0.09002368509893081 + -0.1322447170189405 + -0.2313654657212282 + -0.1137904372765817 + -0.1345582192042777 + -0.5916468699011971 + -0.1974399310317567 + -0.7310498207769246 + 0.0904490285916611 + 0.2617952826851531 + -0.6658800334079958 + -0.2136383312489579 + -0.2474050201719908 + -0.37313985201887 + -0.09261816710249975 + -0.2226843760738902 + -0.3276008787398033 + -0.2650874794759996 + 0.1107475747306679 + 0.2261150250691746 + 0.01410981678350486 + 0.08656220760912722 + -0.223291144823372 + -0.04653183679472674 + -0.0123189017563664 + -0.1241550945158221 + -0.5780305491792225 + -0.2051679551218057 + -0.6380321535686744 + -0.2217327200028662 + 0.1880702651678863 + -0.1374455798500671 + 0.07477579189264887 + -0.230654246917585 + -0.1460761228157335 + -0.351748140673035 + -0.009962655782386361 + -0.4829335787134655 + -0.4047193455733119 + -0.08748337483917695 + -0.03324537104327262 + -0.2107543464561359 + 0.04541561517782763 + -0.1206787589924748 + -0.3716068785062409 + -0.3374418396412748 + 0.1726760188136365 + -0.3308066332358634 + 0.255170315489397 + -0.2759676806557681 + -0.04273612238743313 + 0.1552226463334661 + -0.5278672766348809 + -0.5171652498932222 + -0.259448482300692 + 0.07732678154058592 + -0.5486383408282367 + 0.314303831825362 + -0.2208393588601793 + -0.04410650703985628 + -0.2222334863746301 + -0.4153149275231512 + 0.2285908136142874 + 0.2151545018434103 + 0.08146538307396635 + -0.1900672020132375 + -0.3466077795322671 + 0.03569483143576228 + 0.1384705152199227 + -0.3207737890095315 + -0.1944937775285996 + -0.2662333462037326 + 0.4404826946611061 + 0.08773299284947769 + -0.09194271179202586 + 0.1281029509325907 + -0.01978898548302627 + -0.00775196992546068 + -0.1741854317807355 + 0.3259848025224046 + 0.04401697403542181 + -0.4975007188752522 + 0.1436066122471584 + -0.2219367402569576 + -0.1000778091158833 + -0.1266845224851695 + -0.09121927167550367 + -0.3601844598365169 + 0.2486687523844783 + -0.03584302241113982 + -0.09127580032417015 + -0.02447346217466925 + -0.4224191129196516 + -0.4131361763939417 + 0.203067049236413 + -0.3012140924559434 + -0.01364892432756534 + -0.4814532324701255 + 0.3170718278420939 + 0.1587410603006361 + -0.216424363157273 + -0.06895458529347577 + -0.4016696264415105 + -0.3622807926391333 + -0.162427061007282 + 0.1434223168812234 + -0.3712616885015544 + -0.5024324778723644 + 0.2529794125252718 + -0.1779998772475726 + -0.7279837946956683 + -0.4446830120824465 + -0.1750441732422112 + 0.1146496243364256 + -0.4959298585253443 + -0.163924280908683 + -0.3573746569560586 + 0.3814031678509575 + 0.05951062074438399 + 0.2997662033054271 + -0.3855924523817795 + 0.1029731263097956 + -0.1208204919484131 + 0.08569036493936666 + -0.1509810931506685 + -0.2073591495323373 + -0.2151644795594506 + -0.2827638203076263 + -0.09764470321143262 + -0.6350097962454752 + 0.1677218152331212 + 0.03991765426500021 + -0.3740673754317914 + -0.3755793000001317 + -0.1420218531216212 + -0.3745804350769871 + -0.9402288793052358 + -0.7371490179018136 + -0.199320776234589 + -0.1086466664003375 + 0.2234300207129388 + 0.4520090418359478 + -0.1103738931205903 + -0.2241078313420341 + -0.3088597516010719 + -0.5642512091492026 + -0.4143577903162539 + 1.585769903461108 + -0.0928980419106312 + -0.1639243683643334 + -0.6609187513382873 + -0.03370139779658248 + 0.3998306293641981 + 0.008523386283980328 + -0.3397761104272032 + 0.1596395829533195 + -0.2321779744920058 + 0.3470263743593928 + -0.2987069271702892 + 0.3727308282033386 + -0.1411837021579574 + -0.1765649647109546 + -0.4840684675721143 + -0.5546491976224101 + -0.519672020666552 + -0.07326886758992969 + 0.2264171857621609 + -0.3077200915977026 + -0.5490934046857481 + -0.6020907699945578 + -0.6160437088271168 + -0.2187029258141679 + 0.1405764638862422 + -0.093012829466791 + -0.2969089595390227 + -0.7501222899942074 + 0.2866256906799098 + -0.2387046251713708 + 0.04525727454160814 + -0.2667324397508992 + -0.5717447658970759 + -0.1781952509044608 + -0.5443454325827244 + -0.3391144945543338 + -0.3844961989382008 + 0.01499988326006704 + -0.3258333496747647 + -0.2592405706859131 + -0.3504717802952628 + -0.02668263132768721 + -0.336942418143115 + -0.008899326508741834 + -0.4064724339785245 + -0.12176728147033 + -0.6585179601696123 + -0.4894753878178747 + -0.2442924820600981 + -0.3920391396714519 + -0.5221616690504185 + 0.08143575493923301 + -0.4243781097009219 + -0.0783176392163677 + -0.2195665841694698 + 0.1850063913193356 + -0.7196111874495446 + -0.3179532141429242 + -0.01565370585505655 + 0.005846773803302997 + 0.01335231182307772 + -0.2718325851744277 + 0.3462680224808091 + -0.1959387716606182 + -0.5438993329772722 + -0.4787343953438634 + -0.06678603417674459 + -0.499921571639358 + 0.09815744930648497 + -0.2129229731611965 + -0.07730212367128855 + -0.5485743205851044 + -0.5452923246924926 + -0.3020803622176061 + -0.1591960143215016 + -0.04956358398817994 + -0.0290568894388576 + -0.008253192309295925 + -0.1955745058619006 + -0.04618583863778489 + 0.1091612752012542 + -0.4619001610364459 + -0.3692202542164156 + -0.09988786470240667 + -0.4692197245166221 + 0.1914676051407242 + 0.2121749482849875 + -0.1149307010526159 + -0.1904478657477881 + 0.2462014858522821 + 0.001754223755763481 + -0.08480309741901883 + -0.2127612683438606 + -0.5118184167687053 + 0.382347513962762 + 0.03808150938029006 + 0.2518807181589469 + 0.02154858415273547 + -0.3893449322968922 + -0.2167216909410216 + 0.3860177129811224 + -0.08499909511413424 + -0.3887432617560126 + 0.3708619457636211 + -0.3120436016510948 + -0.05299917601938802 + -0.1099162929881584 + 0.3817873712974926 + 0.341076861738471 + -0.5291531398780812 + -0.3218978604160307 + -0.1569871545851364 + -0.3389052762012951 + -0.8543496902114009 + -0.4430601170393201 + -0.822917007835629 + 0.1578091180914681 + 0.02356555643550554 + -0.7311591075724099 + -0.02046745063084701 + -0.2556341900660989 + -0.4334977374873441 + -0.2172836075673819 + -0.1004610402281179 + -0.5995114010789439 + -0.1580215576663957 + -0.2700160753907077 + -0.1791718769204184 + 0.10433318172727 + -0.2628705816799846 + -0.1686570115607318 + -0.3068685281060631 + -0.09814630618918101 + -0.1497385025023432 + -0.4074351212448353 + -0.3334924678781389 + -0.6538958399570722 + -0.300561782996361 + 0.1822896782480434 + -0.1139468491097467 + 0.03539343147907053 + -0.1550662450716123 + -0.5397131238570544 + -0.372181867218021 + -0.4674203237608217 + -0.6545563178051702 + -0.4229395670115984 + -0.04113516245428499 + -0.5451085318148088 + -0.511592875468121 + -0.2840266659950414 + 0.0106744015890542 + -0.4554353508680534 + -0.3388074378591223 + 0.06221199312929226 + -0.2740359519549297 + -0.3067440885546456 + -0.2550129301256622 + -0.2390063345835033 + -0.0006035686096761179 + -0.605677444649717 + -0.119793771027347 + -0.2750243242962616 + -0.04642902449794497 + -0.6308490936483154 + -0.01242161786196535 + -0.07132997202448933 + -0.0887428962759793 + -0.2325238462713042 + -0.9047463541424298 + 0.01658182378927922 + -0.00757330869321584 + 0.1593916913105907 + -0.30865992061819 + -0.3331606028431572 + 0.1263895129933455 + 0.01961474297915897 + -0.3470257833748221 + -0.5424716805812152 + -0.2009709154582145 + 0.45758918922306 + 0.2787925860775491 + -0.2414443397955571 + -0.315930801341089 + -0.2764128272374969 + -0.3745237272689381 + -0.126159677981048 + 0.4191869601185408 + -0.6784266104832994 + -0.5163194826192089 + 0.05122030675741623 + -0.3439245695363883 + 0.1948868616089859 + -0.195621240269816 + -0.2138035569149919 + -0.347389993572753 + 0.339360043845781 + 0.01605039416612359 + -0.3309417321826002 + -0.3241029873528691 + -0.2576945702651006 + -0.3775080322103062 + 0.1443789467073577 + -0.2115000012605343 + -0.0632786938770744 + -0.8588933711020734 + 0.217274860245064 + -0.3226043112026534 + 0.01771453443535823 + -0.2761564016940267 + -0.3606438760377993 + -0.4118506441057463 + -0.2423832117304276 + -0.0887804850759015 + -0.5729156705116153 + -0.6925410607046041 + 0.5280927917298445 + -0.2823300145568775 + -0.9402331275720441 + -0.1997246501346932 + -0.6724763279724075 + 0.06182904160979734 + -0.708049809297232 + -0.259721293167383 + -0.3865451274527018 + -0.1284111529569806 + -0.3514575322321374 + 0.08207950137162345 + -0.09598541532096631 + 0.147289309646151 + -0.2497369372424541 + 0.2156248484000855 + -0.2658245768023106 + -0.572600223736922 + -0.2521990907983624 + -0.4295099510742876 + -0.04681170516341528 + -0.7328427675174419 + 0.1884437179260753 + -0.04673741402675256 + -0.7794252860778346 + -0.6598692557606886 + -0.1671782095543159 + -0.3821492234558344 + -0.9238147067806809 + -0.6916296008663123 + -0.3402834544006016 + -0.578286567452837 + -0.08526704879707259 + 0.4962274795435372 + -0.7861315151895858 + -0.2066634650164923 + -0.5337220378425992 + -0.718410100444599 + -0.504459492665439 + -1.781827984730382 + -0.009947068886489769 + -0.4232115708025747 + -0.5426458863517839 + -0.5264455047333106 + -0.02365578538253354 + -0.3068997345092218 + -0.5150887200116396 + 0.19076241356687 + -0.1554067325416549 + 0.3969325754490018 + -0.3676212471563032 + 0.5257695833701596 + -0.274742496467984 + -0.1857001610880882 + -0.1400976841123476 + -0.3617743663956622 + -0.6082153702179874 + -0.03632788515964308 + 0.02645797539322557 + -0.4161029360544639 + -0.7431684755220693 + -0.664251865974368 + -0.686806875659062 + -0.1496536443263377 + 0.190202432826203 + -0.1443255792224843 + -0.08102931935739026 + -0.72094662197717 + 0.004892581362082224 + -0.299705529614719 + -0.01696646447822541 + -0.3272883990347764 + -0.4905533145913219 + -0.1813396174116535 + -0.4071266089152618 + -0.5655314771866083 + -0.4955683794089641 + -0.006248670385064545 + -0.3033017414216436 + -0.5888400949273649 + -0.4074841816642161 + -0.5959435509593141 + -0.9107791944897182 + -0.3349167971705578 + -0.7373588861608363 + -0.6026594024957698 + -0.6107404965543706 + -0.5003765155757252 + -0.2098611070589861 + -0.4021373027965684 + -0.8970043375612039 + 0.08397910064022965 + -0.4382484290758023 + -0.3301399368071711 + -0.1242664808119831 + -0.2566178601993747 + -0.8580139120956334 + -0.3507095368583322 + -0.3811768675654083 + -0.399773831124957 + 0.1689071027451845 + -0.1953723184008203 + 0.3067860909489342 + -0.5295403789461324 + -0.462947842632857 + -0.309595415132518 + -0.4885207249855884 + -0.3616981532296132 + 0.1724954091130182 + -0.2242279567779056 + -0.1011815074360616 + -0.6491739385864949 + -0.586984527587308 + -0.3778323314108448 + -0.09455214175017755 + -0.1417058751390151 + -0.2992596095016197 + -0.03766037803092157 + -0.1127711321594186 + -0.148458127618688 + 0.2093510540750044 + -0.4264534725673995 + -0.5603598915878025 + -0.1225630439665603 + -0.4815789276416481 + 0.1703550775539186 + 0.08599999366535897 + -0.4500855357806468 + -0.299901613610683 + -0.006269558339009458 + 0.1243574071130169 + -0.2346236097390691 + -0.08636255906208028 + -0.2229581332903815 + 0.2823707262727844 + -0.2397291346814265 + 0.1680025127720532 + 0.3012079184576376 + -0.7086369232392157 + -0.6408726543683755 + 0.3433000709787449 + -0.1575065203138797 + -0.2867059557405419 + 0.2773035145438126 + -0.2150019370514253 + -0.4243012461071846 + -0.05769483473691139 + -0.07319840475241103 + 0.3170796895196715 + -0.5671667329225263 + -0.3613263866052935 + -0.1833799785322691 + -0.6008257845500781 + -0.6653095750697096 + -0.6002023243499531 + -0.6657416600414023 + 0.1797629486941266 + -0.3595463967012169 + -0.6608457903818953 + -0.1399092453423791 + -0.3320523822637252 + -0.6346831609524493 + -0.1126116635467497 + -0.4430829785354419 + -0.5485231708125181 + 0.03204657762249968 + -0.5301733635083953 + -0.5816943497436409 + 0.008806774026283262 + -0.5491988821134777 + 0.08435077825563157 + -0.4249142318330439 + -0.4528829190479355 + -0.1372350565664413 + -0.3979607906751999 + -0.2736356445295965 + -0.6591575170066557 + -0.2028113340747752 + 0.3093224396829657 + -0.1191120114081912 + -0.05310542061942999 + -0.07089508746778765 + -0.8108684520555332 + -0.1785032426837721 + -0.5999447934883962 + -0.6111411990278564 + -0.4186274799455245 + -0.1996346316510463 + -0.5072772867718675 + -0.5085715229962611 + -0.4783727689671217 + 0.3888878648421634 + -0.5018817073580097 + -0.1710123961143074 + -0.03440537061758202 + -0.6307201710364533 + -0.7624669294232587 + -0.1576758872803966 + -0.1730081850814273 + -0.02625730250783562 + -0.5651390390100943 + -0.2542031839819762 + -0.3311672194039363 + -0.07320000952316806 + -0.7051065686715809 + -0.5397917702212847 + -0.02024915602074184 + -0.1898657938494608 + -0.314988435251115 + -1.106120080454726 + -0.5480091149859121 + -0.09145879212478093 + 0.1440405642236308 + -0.5120847002837695 + -0.05440699605913334 + 0.2362600119337995 + -0.2498941318550015 + -0.3758131420797248 + -0.4106673983087781 + -0.3363085217087289 + 0.6044613757751727 + 0.1122602238867986 + -0.3170173832997 + -0.2052360563028308 + -0.3537423350446363 + -0.3191986995735654 + 0.01210117158462355 + 0.2407197443137293 + -1.131072648759672 + -0.6094826423122511 + 0.1481031201204994 + -0.2816758046960969 + 0.1752267227585191 + -0.2742201391037056 + -0.650284605760318 + -0.4139406904977087 + 0.3116073296461769 + 0.09366767815532326 + -0.6537020409696733 + -0.5264410585863214 + -0.6306669892186386 + -0.2142258307113107 + -0.2299817083155755 + 0.06915493757999686 + -0.1521691785608325 + -1.141583345649978 + -0.06592206427003312 + -0.3126744427081004 + 0.01693288377691876 + -0.3528965617401257 + -0.1314278329686176 + -0.5596825145110919 + -0.2598449364567456 + -0.3186944506137265 + -0.6657774294296043 + -0.6689401126733523 + 0.8424123812819385 + -0.3009561611668924 + -1.064671667809632 + -0.5656834873141398 + -0.7752133072999027 + -0.1241937641920823 + -0.6374480002381808 + -0.4316929876739758 + -0.5379254658864181 + -0.1328429314433819 + -0.5164809431613604 + -0.2962416807611852 + -0.1095985366281921 + 0.1207874243767804 + -0.6628900788488759 + -0.1351168325674617 + -0.2640325389261486 + -0.8452106536516678 + -0.3278363941281444 + -0.5382437306891634 + 0.0007679836840912218 + -0.4236868179998368 + 0.1319238561852083 + -0.2514732603231891 + 0.00682872503865941 + -0.2460237822275235 + -0.2149518213119463 + -0.3853157704397552 + -0.7518385681609683 + -0.5661407784010941 + -0.4055167927140272 + -0.5343414090579431 + -0.2868332194461589 + 0.2708073279502483 + -1.022867290643607 + -0.2684839686071238 + -0.4610225988546588 + -0.6772542738231266 + -0.3544382407374108 + 1.740030988687096 + -0.2402757352641925 + -0.5008001701776205 + -0.32203566623503 + -0.420424818079375 + -0.5527956962790427 + -0.4165025225562441 + -0.1934917831570036 + -0.2564252939818574 + -0.3979042505792373 + 0.569503383874053 + -0.3992567834737347 + 0.5897134182343675 + -0.4717142696950412 + -0.1879011738315803 + -0.3296751719897661 + -0.04853534424595358 + -0.3196629319664885 + 0.01616278646428472 + -0.02518437276958412 + -0.5159949290714172 + -0.4637381442910093 + -0.7480603122998082 + -0.593565034849613 + -0.3443225637849446 + 0.1915663217760353 + -0.2208231019276707 + -0.0229822183777675 + -0.9744571245769105 + -0.1626221200879218 + -0.3515559219094913 + 0.03383880333558515 + -0.4688044937671148 + -0.7618252549229642 + -0.62682769836385 + -0.5754922484276397 + -0.2888300568057754 + -0.572224317416559 + 0.01053109933068843 + -0.294445312607977 + -0.7097400471505686 + -0.3989451628754628 + -0.7911465174554497 + -0.8293220722254347 + -0.2840166022341136 + -0.5712601088393791 + -0.4600099221423827 + -0.28899931163757 + -0.3643181064797407 + -0.2225982521597181 + -0.2438786397524137 + -0.9357264224665949 + 0.228355580792485 + -0.1621760245473221 + -0.3049375648757576 + -0.02225913657565592 + -0.1694873664214451 + -0.7959264250443929 + -0.4139968176207957 + -0.4110033725326739 + -0.7852385808451339 + 0.1283921083206729 + -0.1463796515185316 + 0.2271431064471801 + -0.5617095218394167 + -0.7841145258499482 + -0.2560159493630336 + -0.5580690917179528 + -0.04531553057782736 + 0.3554651982974579 + -0.2229454527347418 + -0.1027446492423381 + -0.6148578968220384 + -0.3213478564924183 + -0.4648935364962582 + -0.1411256112089259 + -0.5837217247480977 + 0.147878190493986 + 0.2097076500532646 + -0.06846971738883641 + -0.247471001276119 + 0.5637195559861582 + -0.8643569774815417 + -0.5739224547249889 + -0.1211870337370245 + -0.6808082790534996 + 0.0666681877316912 + 0.06161818894203498 + -0.6313891561168232 + -0.4116426898980775 + -0.1467126937197818 + -0.2977466389072961 + -0.3153989022423644 + -0.5208853164006397 + -0.3845323102999652 + 0.280267202921041 + -0.6839282700139054 + 0.1757954743509033 + 0.2795987531029381 + -1.063435226925195 + -0.7635577498452711 + 0.4197159489910926 + -0.04269171867875766 + -0.1163816233067556 + 0.3169323876707662 + -0.3241239598066025 + 0.02207212575000063 + -0.02996874692232253 + -0.4523229984245173 + 0.01235470586480735 + -0.4904427974491405 + -0.3480502876861254 + -0.1594231677310244 + -0.6080547005840844 + -0.1753453575408354 + -0.4323488361306168 + -0.505339485231958 + 0.1550320090461448 + -0.4788857991812676 + -0.7416837536959027 + -0.526284161501043 + -0.3205144331745952 + -0.6799907880853793 + -0.0004602501180474434 + -0.3553702825004848 + -0.5628476691497847 + 0.1831584813954614 + -0.5833876316757762 + -0.2385667806020592 + -0.1435223220691675 + -0.5862099375816562 + -0.006706504552293172 + -0.4107388300348321 + -0.4971982875136436 + -0.197366562155806 + -0.7940342484313364 + -0.1969251071604586 + -0.9874351191383243 + 0.07926008935697504 + 0.1646474683723194 + -0.1233008039743702 + -0.02671002162957524 + -0.1444779380085388 + -0.8378694132281145 + -0.3031219709420606 + -0.4809574349308396 + -0.5928992192700092 + -0.4413021065317886 + -0.04918086472912069 + -0.1076738850473241 + -0.3879281706209609 + -0.5227018007203815 + 0.3082199540555409 + -0.8051717417915679 + -0.1150540598055636 + -0.1704053487569717 + -0.8442359408404969 + -0.7832043444645047 + -0.1760183397472159 + -0.03972588631436266 + 0.1985375297124761 + -0.3433438205288021 + -0.6022461326730766 + -0.3832753364025572 + 0.02496989821628015 + -0.7482856620325489 + -0.676472325144241 + -0.1995175329101491 + -0.3055061345658232 + -0.3525741657072834 + -1.041952251483809 + -0.4833379927283012 + -0.1631391027722319 + 0.08717001671536372 + -0.5758173054151819 + 0.2556821980832631 + 0.2893202308655086 + -0.3180363901873887 + -0.3543792204057355 + -0.1415516959141055 + -0.3925201797698654 + 0.8471840398193545 + -0.007706221773311706 + -0.1963279733293128 + -0.06959797801059125 + -0.3439763571075633 + -0.1369718553100855 + 0.08363263051704599 + -0.08420122646260238 + -0.9430659754739588 + -0.4837684467461363 + 0.108912306293059 + -0.3097210873343849 + 0.2073936141374547 + -0.2969534935970397 + -0.6893898771050506 + -0.3805016869987031 + -0.01829813528337139 + -0.03519004420106402 + -0.4904205191547068 + -0.5237925240566278 + -0.8873934736899731 + -0.1647033558058378 + -0.6895951797493588 + 0.1969087071731084 + -0.1431303983363662 + -1.199648901972244 + -0.2292936600652613 + 0.1048424274021737 + -0.211285411441128 + -0.3412345589704287 + 0.1421968005512652 + -0.5929397675682737 + -0.300151981810605 + -0.3521789047934598 + -0.512952562361777 + -0.3186910232639853 + 0.9687960781341542 + -0.3247884445108192 + -1.111584493802074 + -0.3401393556610821 + -0.4732730076001035 + -0.2112119737469602 + -0.6182892105283664 + -0.5317519963536463 + -0.5122297506852407 + 0.1991472282966215 + -0.3521110322185296 + 0.07007926399907323 + 0.1071993659132263 + 0.08979388021070796 + -0.6263631267375758 + -0.3159070728631599 + -0.621762198439926 + -0.8270000722327756 + -0.3211575912606422 + -0.4743296938417983 + -0.1040256616831242 + -0.1049837439919935 + 0.1657019051342271 + -0.3762664671296157 + -0.470896309465375 + 0.1131506048092131 + -0.2081354288090403 + -0.3751672573201461 + -0.7475183680699227 + -0.3429889606103283 + -0.3563272169382081 + -0.193391652912252 + -0.1531689089457126 + 0.01097693395417735 + -0.8701040648264207 + -0.3143213515089616 + -0.320219666872623 + -0.592222215133461 + -0.3119573320575327 + -1.781973028558838 + -0.5607983807665291 + -0.5284186051541483 + -0.2431205520419281 + -0.3293907359360963 + -0.844879692017794 + -0.3785271889603082 + -0.01566285948976559 + -0.6479386231714839 + -0.4968833348626299 + 0.7222550173615462 + -0.5314642510724801 + 0.4308429549802154 + -0.6232325490933887 + -0.182016847791158 + -0.8778392013648422 + -0.1639641219509562 + 0.03408601202469844 + -0.01649806840710853 + 0.08165899544008666 + -0.7182053520196864 + -0.0282191147370792 + -0.5870543552588785 + -0.3231940518303731 + -0.5771586795985312 + 0.3262405283444714 + -0.2528153413391997 + -0.4082394060139936 + -0.7741023157948116 + -0.1681944551198781 + -0.409362942909045 + 0.1675440584613964 + -0.5640719656890355 + -1.055730129940361 + -1.098571488379675 + -0.8975787973673068 + -0.03772469550847653 + -0.5642342418592303 + 0.008230844877315392 + -0.3339261354764625 + -0.5514432759140413 + -0.3581455261509393 + -0.4072398822900626 + -0.7505923501963231 + -0.4133824271519346 + -0.2502443089715727 + -0.1859781500659672 + -0.2507778584384046 + -0.5768442401927268 + -0.172494219696996 + -0.1370585867667568 + -0.7451345314503817 + 0.3863714854580726 + 0.08592667913501936 + -0.224872090415018 + -0.3867075059046672 + -0.01995574410190462 + -0.7792667864810917 + -0.5139905686401676 + -0.1542818303227253 + -0.9569043036713922 + -0.2697091330581493 + -0.1987512335898944 + -0.2010240181995746 + -0.3898078563984238 + -0.5728928421282474 + -0.4898382537117549 + -0.6661950745854164 + 0.2316645697315715 + 0.1451958537847786 + -0.285186100538286 + -0.1548825383639861 + -0.3606243712905282 + -0.04309501997003859 + -0.5252121926059879 + -0.08087819685630879 + -0.8435507862497488 + 0.4306854850221897 + -0.08238840393192921 + -0.05041650085296915 + -0.01158433575335821 + 0.6521341473703037 + -1.047237039308981 + -0.3746236902847343 + -0.1082794913183117 + -1.031700987750881 + 0.1391159630165882 + 0.1736528264501267 + -0.6512238773038403 + -0.4587991036038348 + -0.1340821280386915 + -0.7334583616678994 + -0.4458441551671066 + -0.837471432556554 + -0.6672799757736255 + 0.2448374172288726 + -0.9024474589734426 + 0.1023670755906258 + 0.0292058596005524 + -0.9520214971401303 + -0.8268143038010669 + 0.2972605217114852 + 0.1453064233583261 + -0.5232784383932808 + 0.2086008331921708 + -0.7627467577788207 + 0.3941662642328789 + -0.2286381155884264 + -0.5870456814615304 + 0.102084148967303 + -0.4329515063089142 + -0.3906233582382577 + -0.1731692891447 + -0.462936283622991 + 0.2186150787660332 + -0.5378741730398333 + -0.5513110470695967 + 0.08792702355002706 + -0.5160325021276126 + -0.8038774266202716 + -0.8673068591619917 + -0.2800402211052486 + -0.5071812287055846 + -0.245761552277381 + -0.1131894656146579 + -0.7111469043039585 + 0.2949153372857375 + -0.6125145957330751 + 0.1333191507641706 + -0.4143036664128203 + -0.3881311020441194 + -0.4536636134855772 + -0.6501534428375323 + -0.4587908045668875 + -0.2262689907292591 + -1.008930698162811 + -0.2858199286034775 + -1.097091975238689 + 0.3349940031359749 + -0.03397858581056419 + -0.1115325585421367 + -0.1536060218366431 + -0.2472757970660318 + -0.9552163802897028 + -0.6360437725640494 + -0.2415017541557331 + -0.587043818741025 + -0.4349002239176226 + 0.05466084891586871 + -0.08379992506168299 + -0.4337862151309793 + -0.3523864784159469 + -0.2180967687295187 + -0.8293383325079787 + -0.3981414008486881 + -0.3406100475235269 + -0.9146022384063078 + -0.4776784098582947 + -0.2444239310349579 + 0.02509980574020787 + 0.01141825131356056 + -0.4052794734982313 + -0.4729987232950348 + -0.4093980513685815 + -0.00873726058681297 + -0.7712260881429435 + -0.7848996302391045 + -0.4474293883176877 + -0.4323587577203974 + -0.3591563401798847 + -0.9546891379024977 + -0.4272933483664859 + -0.06972562127096517 + -0.02149647229712578 + -0.770948698054748 + -0.03291204158136948 + 0.3803140241482079 + -0.1873962583031693 + -0.347983988323403 + -0.1636512977496206 + -0.3091525419691572 + 0.8900416145331014 + -0.1743739584560785 + -0.2799925329935282 + -0.2953298210434973 + -0.450373929504557 + -0.1897727562191744 + 0.1512685793668392 + -0.2564901069991625 + -0.7598665348694464 + -0.4516988612050298 + 0.1068511089079621 + -0.2808640885633978 + 0.08429370500173265 + -0.3006954281227031 + -0.5940605997954104 + -0.4359973149611513 + -0.2442812926963645 + -0.0329967553759234 + -0.2558588863449351 + -0.5317364343041211 + -0.8531979377142996 + -0.6747777970265376 + -0.759844933067973 + 0.0006778703703523043 + -0.1294741974933304 + -1.106916969987646 + -0.1352047865966687 + 0.08682798495941844 + -0.5157487159470723 + -0.3502479771286062 + 0.3010730983680521 + -0.5465252622325496 + -0.3861814509901219 + -0.460932413329754 + -0.3924467851902882 + -0.003125988376217017 + 0.7091393647100384 + -0.3071080884322199 + -1.248602155389827 + -0.6026747990886756 + -0.151398152882901 + -0.2826794853998861 + -0.7794898241130669 + -0.5593715976627073 + -0.4852336979367511 + 0.008309981183236928 + -0.1021599316578544 + 0.3411885873017287 + 0.5081079556857369 + 0.03733243284709165 + -0.3308654045131658 + -0.2466537274174862 + -0.9377014554868648 + -0.8369771035990859 + -0.3451759856061667 + -0.4415002397679108 + -0.2260156389975992 + -0.09391867372990505 + 0.20536671518883 + -0.3820615019536124 + 0.8603809226716443 + 0.04649318982692087 + -0.158594619703022 + -0.3744326803384477 + -0.9125369928504006 + -0.2378369680554814 + -0.3006028796512427 + -0.08976209282829463 + 0.03878589158372698 + -0.2571253410084418 + -0.785713420861162 + -0.3177862219631656 + -0.2314554537666901 + -0.3843821789143249 + -0.4873158910290698 + 1.867504138689031 + -0.1400122810502813 + -0.6753642256336548 + -0.2131931662576885 + -0.4222201678406883 + -0.992839970337568 + -0.3564598873179906 + -0.1984565326015064 + -0.8003576707711179 + -0.4047668580826831 + 0.7674033625513189 + -0.5379221398723746 + 0.3200337625725557 + -0.6216122206835325 + -0.1813225694221128 + -1.087091976625574 + -0.261186702356849 + 0.01544308449351302 + -0.2500519919860956 + 0.1441280229092948 + -0.9619638588218969 + 0.1269707449510237 + -0.6043244873826396 + -0.1725858061112837 + -0.6338179309763565 + 0.3837868560834052 + -0.1949495842806335 + -0.758838935074038 + -0.6577446655062089 + -0.1066555349812738 + -0.4665885207142938 + 0.3969287809523685 + -0.692421554516083 + -0.8766299067088819 + -1.222737098832862 + -0.9412237269783912 + -0.1783534432115874 + -0.5793127719721858 + 0.00198151099599386 + -0.2914654072177844 + -0.9132033195906868 + -0.3403370434379572 + -0.1868548302155974 + -0.6710837117043588 + -0.2454886164132825 + -0.1241173018458294 + -0.2881038463860114 + -0.2303714358992366 + -1.015450790887978 + -0.103293216194567 + -0.2492892148066009 + -0.501306977223504 + 0.5467538639021241 + 0.2218582371860424 + -0.2512560586044336 + -0.7542107007949712 + -0.02320318421047902 + -0.8658572514826759 + -0.5559053392767729 + 0.02184836138294483 + -1.020389550090781 + -0.6871829233387893 + -0.3082731594064871 + -0.6241027114402874 + -0.2269937410753727 + -0.7018013596758071 + -0.7708968870449653 + -0.6888896844758244 + 0.4445543856629801 + -0.2511562352753987 + -0.1454995404220746 + -0.2401718120916491 + -0.1373932587443327 + 0.05750814917539201 + -0.5077294001027047 + 0.05337787197100174 + -0.9368218187167636 + 0.3094167643873372 + -0.5086778642578426 + 0.06744163899424491 + 0.1149160751543754 + 0.2772787764088001 + -1.131635194925813 + -0.24299331655764 + -0.1048965486925691 + -1.226254278840357 + 0.2029837279627382 + 0.1659767946555612 + -0.7132139376091509 + -0.4943209625346273 + 0.05117485812238402 + -0.9063858289101545 + -0.4820357410883333 + -0.9985494038759675 + -0.6582131227198482 + -0.1703380258281345 + -0.9928703297273094 + -0.114582736253507 + -0.09210900657241534 + -0.7078960436284223 + -0.9469585751118496 + 0.1005995272527878 + 0.2414918171114861 + -1.09964696711853 + 0.1575427776842223 + -0.8200464232382167 + 0.333162096363932 + -0.3821110116835941 + -0.5101465687146329 + 0.2144853276229104 + -0.512968358020117 + -0.488113300839539 + -0.2231572929378784 + -0.6201640114343301 + 0.2779820537987536 + -0.5104169196537974 + -0.6104312516002482 + -0.01020268160961942 + -0.5220419351288996 + -1.02325893573648 + -1.128840855457466 + -0.2799193428358276 + -0.4285771894615326 + -0.546634031813172 + -0.1516111067465357 + -0.8121415040333105 + 0.4884931648429183 + -0.6067981257056273 + 0.1552447809247549 + -0.559431567530568 + -0.1767958055953588 + -0.5082820086240474 + -0.8587536693663146 + -0.4448482480218933 + -0.190572533645124 + -0.9276026706789513 + -0.3727380520268397 + -1.022288134606446 + 0.5338402697560298 + 0.01606721260939164 + -0.1198185494852305 + -0.4219561200564114 + -0.3629507087479318 + -0.7933746066071081 + -0.839387868910383 + -0.2714587435270597 + -0.6183725771998323 + -0.4406180819036702 + 0.120792154047767 + -0.1751175420400254 + -0.5428664166010159 + -0.2268962176582445 + -0.509221779962194 + -0.8449037912845141 + -0.6846059682233914 + -0.3219151493929256 + -1.034332439008274 + -0.3900501572073875 + -0.2413581968510067 + -0.113597852135392 + -0.3351205767677078 + -0.6361979833288497 + -0.1928292306697757 + -0.43680298624963 + -0.1887923567377331 + -0.8025552691681482 + -0.8822249286684164 + -0.5173636867479294 + -0.5396821401592674 + -0.3784762859892659 + -0.8448706219451347 + -0.5234203882543 + -0.02523284708004396 + -0.03004488642002552 + -0.5911414799190232 + -0.5198729319281616 + 0.3793210414752821 + -0.04253283290772383 + -0.3466682916964748 + -0.2922567493223415 + -0.1092012753827762 + 0.7215290234431692 + -0.3998376566347607 + -0.3785129240010847 + -0.534849131920757 + -0.7159466788797467 + -0.5158517564827039 + 0.2191034254880796 + -0.1687253454842232 + -0.8006633752006649 + -0.04233864925094758 + 0.2140476332785622 + -0.2296165453694349 + -0.2915847379002629 + -0.2888886891570239 + -0.4784622980651279 + -0.4467145960481185 + -0.2256072700117347 + -0.04297332735554762 + -0.3004901990870193 + -0.5309290473258421 + -1.007158475659556 + -1.111196509017678 + -0.4529845320173796 + -0.1409433732378824 + 0.0222587276785431 + -0.820032995490547 + 0.007376701449273282 + -0.09344757451430596 + -0.6575287905493787 + -0.3359023295164944 + 0.5245680980769555 + -0.6068177056063478 + -0.4216118690137018 + -0.5725608766120418 + -0.4132240278745631 + 0.06853942621820504 + 0.3766986723601243 + -0.2236264198419682 + -1.155001748353813 + 0.3835755738205138 + -0.07269001608422644 + -0.2961927238014648 + -1.011602948583423 + -0.5476932202465833 + -0.4673703739609745 + -0.1149249823172179 + -0.3212341778145969 + 0.251035724468793 + 0.5090317567423607 + -0.2018856400356364 + -0.3026056454976902 + -0.1696618457657907 + -0.8511035584348059 + -0.6360251499027173 + -0.3479035685123237 + -0.5099340626202971 + -0.4260193709536283 + 0.01391765724150718 + 0.04716688284851223 + -0.5193920652906535 + 0.1336592645915052 + -0.1157910297988457 + -0.1209061571098737 + -0.3175436010167856 + -0.9144348098228305 + -0.3985852511791289 + -0.3255970899053792 + -0.2155615860397035 + 0.02576505316702601 + -0.4311139406371869 + -0.3922836136710843 + -0.2706420873581653 + -0.3149541713240933 + -0.1009102613588649 + -0.7589114696564203 + -1.781827984730382 + -0.3225388769638705 + -0.6477950476558042 + -0.1705397346900364 + -0.4016639554119894 + -0.9560729763139403 + -0.1062869424071198 + -0.3410653174718074 + -0.6938947223719386 + -0.2531015973304419 + 0.5154964732046285 + -0.4933817747571067 + -0.103099497056752 + -0.3720333613045235 + -0.123252982762294 + -1.055082572544018 + -0.1092166843215198 + -0.2198511401706685 + -0.4913473463108912 + 0.1099251875339939 + -1.123872395689639 + -0.02938743533917771 + -0.5059274709014567 + -0.2227055243212799 + -0.4690992425341026 + 0.3639924227658843 + -0.02027030350821564 + -0.7309819750094045 + -0.7262974959532765 + -0.06390253566339001 + -0.3340042434091533 + 0.597777278013657 + -0.6949221865942922 + -0.4493798828966502 + -1.160855418373404 + -0.7053072891484373 + -0.699276484447522 + -0.4376704852886505 + -0.05167241028317913 + -0.04077780340070988 + -0.599338006731406 + -0.1877316316037821 + -0.2386115078344901 + -0.3960026156101754 + 0.07314693730402491 + -0.0877385462508644 + -0.3490784660286306 + -0.3042342943000372 + -1.04485869334051 + -0.2133530210299411 + -0.3146573130592388 + -0.3321743102554562 + 0.6536809804245225 + 0.3356024170565902 + -0.1934155285213567 + -0.9308302814893227 + -0.03611906779631877 + -0.9231960135360759 + -0.5094190712281376 + -0.2368865955761142 + -1.039908483654012 + -0.8350780325527202 + -0.4063549237358346 + -0.7216287535653085 + -0.283549014328219 + -0.9303673883439546 + -0.9378338521796289 + -0.3743380151152271 + 0.6652621891428373 + -0.6261809288546966 + 0.04919270649906123 + -0.2000238336443852 + -0.3805201612720025 + 0.1070814407263242 + -0.2373341039643005 + 0.1680623173657377 + -0.8636506670044971 + 0.08496989766350729 + -0.5964578505190108 + 0.2616961079899485 + 0.08564325237143779 + -0.03076282855809052 + -1.006776302453722 + -0.4388848296833138 + -0.02522913690806778 + -1.237672975105699 + 0.2268815798631884 + 0.3284199476696821 + -0.6537825551034893 + -0.5222905782590661 + 0.2957512926294534 + -0.9733422277481359 + -0.3595601174139009 + -1.003688310960785 + -0.5937017251294097 + -0.4447872447259192 + -0.8495306072401683 + -0.2914004542718777 + -0.02520211595957169 + -0.5032552818223736 + -0.8935797977110612 + -0.1749640360389038 + 0.2067588852205771 + -1.361739084645942 + 0.01607068850026597 + -0.5986951376148295 + -0.006364519784491229 + -0.418312344602186 + -0.3255628138534578 + -0.05822691441876494 + -0.5470615402964608 + -0.4674344014256545 + -0.166972824355683 + -0.7266288134790206 + 0.003911148183964989 + -0.1107724574764601 + -0.6388237463609426 + -0.3195108977045384 + -0.7914273227694385 + -1.030707884301274 + -1.347581155474584 + -0.2335665650734107 + -0.282266159456554 + -0.6047644519379601 + -0.2647827722254275 + -0.7656455368948109 + 0.6925461994067584 + -0.3355196829331084 + 0.05457413196311294 + -0.6654809206432205 + -0.1716090184197709 + -0.1816043155841315 + -0.8710697445735216 + -0.655246440909579 + -0.1038510359864993 + -0.5753790585325803 + -0.388110581745044 + -0.7701068611951711 + 0.5265629438784175 + 0.1877246111858627 + -0.07274151601928062 + -0.5412953692036067 + -0.4119734917352358 + -0.5366763068137621 + -0.789734438665066 + -0.4938557305258537 + -0.632044272904425 + -0.05377693088462582 + 0.3993417959047834 + -0.2338366100911965 + -0.4892118216335631 + -0.4090155269574513 + -0.7430633627590832 + -0.8739827201153766 + -0.6241417643999819 + -0.3287665353236034 + -0.9053857928987108 + -0.5648028405516894 + -0.3831278412321464 + -0.2667834069307376 + -0.4260095140851397 + -0.5942808972698476 + 0.06590664074879116 + -0.399205686951896 + -0.3525046922510404 + -0.6482042707020442 + -0.6884904318529738 + -0.2322503571731199 + -0.5186819183156427 + -0.259992661918489 + -0.5319560685499135 + -0.5339174568628724 + -0.3743326975744048 + 0.01490145813696582 + -0.2211962027111431 + -0.5308552983355076 + 0.2582853853062619 + -0.04561453043301034 + -0.3664513725843536 + -0.431973756895839 + 0.2651925127001253 + 0.3946610267467467 + -0.4687043765476729 + -0.4124847689797652 + -0.7568303916281496 + -0.8018285259196836 + -0.826153435156299 + 0.2906615985251585 + -0.03724746981708974 + -0.8016310126139845 + 0.4818981906977681 + 0.2721103651715217 + -0.360637480659132 + -0.3872973663893723 + -0.1495220514798854 + -0.1864243586610831 + -0.2102292448691494 + -0.07317014262805463 + -0.09662769112699954 + -0.3378718456832781 + -0.4576579062142558 + -0.9075882353475503 + -0.9219014718538876 + -0.1920685081266685 + -0.116875762912306 + 0.2890653171322882 + -0.4893731464572967 + 0.03429173363179066 + -0.09668863893128976 + -0.7566245638496483 + -0.2809460853315527 + 0.516164339665746 + -0.1102249908103984 + -0.40935018207511 + -0.4571520457708725 + -0.3416521138433671 + -0.06327507390117715 + -0.09480691448373813 + -0.02804242689107814 + -0.8009299785593715 + -0.5118264582900479 + -0.2142006600809974 + -0.1384804766152002 + -0.8475682420452058 + -0.5735110982901541 + -0.3799754077955094 + -0.4477211045778108 + -0.6532779099630316 + -0.03162730375362215 + 0.1448841305296973 + -0.2120341453962263 + -0.4524362540144146 + -0.356780235568433 + -0.5381069203948087 + -0.3039616033589326 + -0.2984008579276916 + -0.4473431779410559 + -0.6485066001685057 + 0.4410917197120264 + -0.1458758574465191 + -0.3815449557405615 + 1.667218727796572 + 0.06210318337388328 + -0.02218373853791181 + 0.3143943544532836 + -0.3695653803667836 + -0.3176914477891388 + 0.05118959850659156 + 0.09008013501068504 + -0.006350069057788199 + -0.01232797267804324 + 0.203935684172132 + 0.2330687614757996 + -0.1624114630506737 + 0.4307269245467064 + -0.4004737420633673 + 1.948549556721081 + 0.3335890928151976 + -0.04192142481248118 + 0.2367004576456525 + -0.1409107966175674 + -0.3436863316219508 + 0.3816399232737833 + 0.007629740452386909 + -0.05620962790570525 + -0.009210520727384545 + 0.04312762633207708 + -0.1045037202332779 + -0.7291590733833684 + 0.275517453291411 + 0.1064432317573884 + -0.2697058202994626 + 0.2235728075947489 + -0.1292678701953861 + -0.3588164388952433 + 0.2089953707997088 + -0.4268770803072862 + 0.1658208426565521 + -0.05874670210612977 + -0.1252114055277611 + 0.2118547821865102 + 0.6627473287282948 + 0.4459429401917344 + -0.2771606877337046 + -0.1775338519619086 + -0.01473339359956204 + 0.1495908131907566 + 0.6746854718412869 + -0.0901262206339789 + 0.1370647022270746 + -0.4456022646206545 + -0.09722113324201812 + -0.6545926777777892 + 0.163677723514819 + -0.0587339326604285 + 0.5543693527837558 + 0.4353403263900784 + 0.5271708111732047 + 0.01003765855487058 + 0.1071942561920385 + 0.3096140164305524 + 0.3841871459387871 + -0.09583582922239864 + 0.01559603339907481 + -0.3155942273850432 + 0.09957052658816262 + -0.1328321173322763 + 0.3564622545695095 + 0.6085146381009029 + 0.5867399596143027 + -0.02250972884758025 + -0.4763015329738412 + 0.1363186111626235 + -0.2266561576288394 + 0.06372520143932857 + -0.2334396842365647 + -0.3265031596549025 + -0.5225730768617836 + -0.2794768981321148 + -0.3806046580723788 + -0.2709384658505899 + -0.3745368673442807 + -0.4919386695331785 + 0.1155843211204948 + 0.9277339631772524 + -0.8220383796531052 + 0.4677961095284494 + 0.1012249285417283 + -0.5689958029104534 + 0.3486579083308017 + 0.3536085222332953 + 0.327297536819787 + -0.3524532775029237 + 0.2478060497053853 + -0.167875376600675 + 0.4683052857569047 + 0.04845777005968554 + 0.151462095439388 + -0.2954444421277257 + -0.1202327210119957 + 0.2654746711195042 + -0.468234794883329 + 0.3119278052564229 + 0.6273311313018934 + 0.2530745559027924 + -0.06309058374995485 + 0.4189488387699707 + -0.4732279941849034 + 0.2094095552707933 + -0.4025186655027134 + -0.1659355510438331 + -0.3177972199941017 + -0.2481462321985213 + 0.006592088157052001 + 0.268780447633735 + -0.2073683427305351 + -0.2106105744749099 + -0.4509560351939277 + 0.1834184809985726 + -0.7661370276962249 + -0.07903346079921088 + 0.04676248215594855 + 0.1237008920290094 + -0.0126499125481814 + -0.05835220431205906 + -0.1588734042816966 + -0.3299073260347327 + 0.08167118119376097 + 0.2478343554039025 + -0.1452099065062266 + 0.1326568406926738 + 0.3491255078998559 + -0.3934174673339707 + -0.5960640115453083 + -0.7910878843462008 + -0.3020982053926454 + -0.8838714860757471 + 0.06568719607260053 + 0.3369431365777982 + -0.2198210057155472 + 0.02881191399440781 + -0.1501821522283808 + 0.9675637896490875 + 0.1967637389689453 + 0.3815388218291317 + -0.2548597206712573 + -0.0560737578407515 + 0.2869704311115486 + -0.2854761498665436 + -0.5950011402363669 + 0.1513743013486433 + -0.009470931824429152 + -0.1739807982033399 + -0.1466233207008622 + 0.5357347876397437 + 0.3074301522098216 + 0.1270808780145465 + -0.3704049340693402 + -0.07042455885511463 + 0.0405713279179636 + -0.3815384053212412 + -0.2997819510430044 + -0.1114667378498817 + 0.7258062829153872 + 0.8700940416597699 + 0.03826930388024562 + -0.1790194202449966 + -0.3616556505927438 + -0.6152504762514582 + -0.2677397580547463 + 0.01079977629521155 + 0.07883747390706719 + -0.3624426716699543 + -0.1527248418632322 + -0.03702200314495983 + -0.08732007815655742 + -0.2271404016758612 + -0.1883027115152028 + 0.3416053441977727 + 0.06418830949057062 + -0.1998428761163998 + 0.1306830477324872 + 0.1391202979596478 + 0.4529091731012134 + -0.1446157003666682 + 0.4358962341170605 + 0.08644203357368854 + -0.08867530401801563 + -0.5120811340035706 + 0.2381130654095968 + 0.182322993378588 + 0.05348965071702647 + 0.1170819346874089 + 0.08019216083419001 + 0.07552243569663072 + -0.0684438818084938 + 0.8236200014683633 + -0.1678402216367604 + -0.04058297968371218 + -0.2326005508457137 + -0.3000381837143903 + -0.6188481131311174 + -0.3212977529986542 + 0.3054848536615199 + 0.02003101442925876 + -0.003896575842105588 + 1.191761661333273 + 0.3339563486035031 + -0.2411313538627305 + -0.1368102385058602 + 0.2099639721724371 + 0.3302646100890316 + 0.279735322187841 + 0.1572125831554773 + 0.1621614227576263 + 0.1361991186281638 + -0.2350784094731422 + -0.2718929744151896 + -0.04033994923534494 + 0.1344402640829349 + 0.08336221947186542 + 0.632881462354837 + -0.008140666772563247 + 0.1272758672873934 + 0.196510462374386 + -0.298640402793001 + 0.1041277340782838 + 0.5678023283084099 + 0.8473197976328795 + 0.006957767088195686 + 0.09493592588800308 + 0.207316106352868 + 0.1114048869767513 + -0.562370393977032 + 0.4970552468469591 + -0.1555858172176586 + 1.338651333090117 + 0.003053498157229314 + 0.1928128576865458 + -0.2186155105026712 + -0.3556388494918716 + 0.02312630631403897 + -0.2670535650055857 + -0.5414662108847647 + 0.01424970636943131 + 0.2005908144610585 + -0.4205355698145358 + -0.1858662228644941 + -0.4665512175475525 + -0.03506163734660313 + 0.2307098331622904 + 0.004312729534306625 + 0.2707557794007244 + -0.4447926297528495 + 0.9127134278553473 + -0.2995522399174017 + 0.1735995315903607 + 0.4425718024777047 + 0.4639329917160108 + 0.08637960391492526 + 1.264868773671721 + 0.4464640301029854 + 0.007233381035124405 + 0.859917942528008 + 0.8262969742469247 + 0.04341658666399524 + 0.8330641227804799 + 0.909348690733269 + 0.9999538158809214 + 0.1665464753088647 + 0.9694422871445725 + 0.3922478417557296 + -1.781448255057624 + 0.03635886860908773 + 0.8076620929999465 + 0.8339334756445123 + 0.3860128823332295 + 0.6653047893610314 + 0.9185296346976854 + 0.6649787949751917 + 0.7825902558010049 + 0.2837037127269504 + -0.3747990077395175 + 0.4214443559395317 + -1.019361892775693 + 0.9171977008345442 + 0.4222361559174124 + 0.88407023912625 + 0.627550531980175 + 0.3566140855934134 + -0.03223197651486596 + 0.4444754817930365 + 0.7198529871401895 + 0.769543155492363 + 0.4522789066520774 + 0.1552051873408984 + 1.087046685118705 + 0.7110449593763254 + 0.8551578745013462 + 0.4445553463014242 + 0.6336985233194055 + -8.666585533623437e-05 + 0.7481389904150876 + 0.6099165356679989 + 0.8441275807205756 + 0.6746478056933407 + 0.7710196583450366 + 0.6015009959469434 + -0.02078264166128433 + 0.9139622734605635 + 0.03649114793601069 + 1.081362510467778 + 1.294925438224664 + 1.364399995326488 + 0.470971101873399 + 0.7400190105755877 + 0.5699287605581952 + 1.004010254105531 + 0.3370758327320168 + 0.6131293665130263 + 1.066506465129122 + 0.75007755748098 + 0.2092889950274849 + 1.188379584369206 + 0.3927020524332166 + 0.8976178226409594 + 0.253591376201034 + 0.4788474086715514 + 0.5846703904079941 + 0.7458621662241995 + 0.9803193405410499 + 0.1373088202715007 + 0.7124319998825741 + 0.001392091297370719 + 0.005439118590977577 + 0.262311652226433 + -0.1294387395986635 + 0.4247535343006393 + 0.4684777559177688 + 0.7152179782510809 + 1.122769290452707 + -0.556571539027084 + 0.7158780094478909 + 0.4802045073119096 + -0.4895153647051178 + 0.7811319855474181 + 0.9588152497290688 + 0.4196819710368834 + 0.4150388135584117 + 0.6482857515970342 + 0.6148584162460666 + 0.7321927360436169 + 0.06685955368278976 + 0.5237996850885736 + 0.5458979798565589 + 0.6853456078499774 + 0.6057305714252021 + 0.7063432420794981 + 0.4090613901948583 + 0.9384325755638672 + 1.422475224972518 + 0.7340220696204048 + 0.3974070122287193 + 0.4291073097870783 + 1.005825244363131 + 0.3983200619644611 + 0.5215660680357879 + 0.1392856995086938 + 0.5911512297254349 + 0.6914181916293677 + 0.6381864477415636 + 0.05556341432556314 + 0.7827245647227641 + -0.4785100388053652 + 0.2664119832167832 + 0.6996726492098401 + -0.1791803178514642 + 0.7268684014643656 + 0.6467564449413579 + 0.7068816095330724 + 0.2160304367590288 + 0.1248403590807845 + -0.01822133643607303 + 0.8960340501583953 + 0.8322632672202777 + 0.7877349704122448 + 0.6127608453581013 + 0.9125600228691853 + 0.06050065398089624 + -0.5814533023644182 + -0.3861156330785092 + 0.7708663019767132 + 0.1414340489287589 + 0.5450846421816883 + 1.038949892081503 + 0.4174288596040157 + 0.6038789998183522 + 0.8250064010704237 + 1.11633891363245 + 0.6408815696753317 + 0.9088580805829342 + 0.7197199404882286 + 0.1852800172254349 + 0.7500042345480682 + 0.6006719336512956 + -0.1501357023317271 + 0.394046806730308 + 0.5674422352507514 + 0.1304522816363141 + 0.5481581118181026 + 0.6648882198575188 + 0.4502490682344322 + 0.4188941087144956 + -0.008164313196871244 + 0.4794370562070326 + 0.7040197300011987 + 0.1877608974045845 + 0.1910932773547232 + 0.7258251041884094 + 1.338647325753172 + 1.3061328441664 + 0.6580938987572295 + 0.3064888139023139 + -0.1279381299652183 + -0.1440544070168745 + 0.6855176548603273 + 0.8451296607375113 + 0.6977692058261843 + 0.3177587836652486 + 0.6277976642860534 + 0.6384007278203387 + 0.1512017510970298 + 0.1909791050629819 + 0.3696613702906053 + 0.5423921235811779 + 0.8189746404472315 + 0.1927059080312683 + 1.122373108673155 + 1.100572668977905 + 1.091448881157351 + 0.3864913664206477 + 1.29530959251389 + 0.8166113995733907 + 0.7601671784301625 + -0.2943511055448276 + 0.4917982436421829 + 0.6232040439503094 + 0.8468610412307204 + -0.05076225304297343 + 0.4823821786251634 + 0.9086852725808422 + 0.7046377387435105 + 1.242050893449605 + -0.7175982302830722 + 0.7622778304151561 + 0.1487060867832971 + 0.6084926229448413 + -0.2617814820307586 + 0.6290740543293295 + 0.2531324541004852 + 0.09820565686203631 + 1.193013779567532 + 1.494944274248078 + 0.2742953038453484 + 0.1402216542798266 + 0.3435783831149599 + 0.618862358885921 + 0.9138941426379912 + 0.7181690558115195 + 0.4396937723365966 + 0.4221474844300872 + 0.9678478824954682 + 0.1621521255176283 + 0.5450861789392766 + 1.068244577362342 + 0.489124356812478 + 0.330030433503413 + 0.8970494954352911 + 0.5013533174532329 + 0.309797772279065 + 0.6738041032434924 + 0.6227668595077965 + 0.5713027065599533 + 0.684893885478556 + 1.668225806816082 + 0.6859151920623758 + 0.8158011224900357 + 1.024473169971108 + 0.5605174526484484 + -0.7576389300488497 + 0.9096875215211347 + 0.6175767372236864 + -0.4161537577909997 + 0.5088495346896563 + 0.5476722851792211 + 0.6339601342061658 + -0.006306045422751316 + 0.5799397740036482 + 0.4713993384867219 + -0.083403128637816 + 0.4313779446126474 + 0.6510757062085264 + -0.3388413420791607 + 0.2626113689451582 + -0.3569649977516132 + 0.50820676068601 + 0.8229394466911507 + 0.4958243200831756 + 1.234369408535352 + 0.09407623276619048 + 0.16842663485555 + 0.2002091519936368 + -0.07338891003129742 + 0.03331177114379679 + 0.06963817063415607 + -0.05666121342626853 + 0.08655782188589418 + -0.01629413987509927 + -0.0332371260118988 + -0.02941861722641498 + 0.01738958082197578 + 0.1508821012348263 + -0.051592030018763 + 0.2067810222519689 + 0.05302820677562026 + 0.01475648246371792 + 0.03010009527862536 + -0.1648663516653107 + 0.0986444033843535 + 0.02027653632157885 + -0.05078959067312729 + 0.04004260342727669 + -0.2910429917514142 + 0.009850227406214163 + 0.1586227363125275 + -0.08533163081359228 + 0.1673847065407495 + -0.0917935042165738 + 0.1496801847004745 + 0.05771147395976754 + 0.0631735402019261 + 0.02467558167012938 + 0.1587463118517278 + -0.03870559009042487 + 0.05765655119519951 + -0.05502951990483894 + -0.3012790946012868 + -0.1039280495160258 + 0.1063983049323238 + 0.1299338848245758 + -0.003281233343411412 + -0.06988172596811287 + 0.02815284661452942 + 0.0654020521108339 + 0.226333928109976 + -0.8343562552992259 + -0.0002100803877835796 + 0.02684384062962547 + -0.1219953203155064 + 0.06685253359104405 + 0.1429352102978557 + -0.005442904517195468 + -0.09786802994119191 + 0.1052384838435717 + -0.03206215886241107 + 0.2012229204149918 + 0.07186077200532717 + -0.05932874527873284 + -0.04265924879392123 + -0.005029992987120322 + 0.1776225785436245 + 0.03883419764649802 + 0.08355110602415086 + 0.05911197404941929 + 0.02744318552902593 + 0.03314821072530822 + -0.1156332194681546 + -0.07758888949702572 + -0.1623300604236726 + 0.0005639166436980795 + -0.09556544175099256 + 0.194410794896442 + 0.1358244714355086 + -0.01425257479015681 + 0.09425253927267592 + -0.07385767853002158 + -0.3628988036168848 + -0.2146645370879713 + -0.0401558831442899 + 0.2023585303653781 + -0.09606575710809313 + 0.04378813468096158 + -0.02788479011315963 + 0.3519728163930858 + -0.0001313508494149237 + 0.008423859760551206 + -0.268183675166824 + 0.2300554358278003 + 0.001880330496123822 + -0.1476457270882015 + 0.01403761966618388 + -0.0630537502894067 + -0.2041918066761578 + -0.04062467047844028 + -0.1682476818663452 + -0.1031124765729317 + 0.02918936363321958 + 0.05452945343404456 + -0.1460370674413418 + 0.01368646691490838 + -0.1899527644748964 + -0.01702910558237531 + -0.1713812863587018 + 0.07653604731612897 + -0.06494812002629886 + 0.01790638988306824 + -0.163161299634012 + 0.4186091936942767 + 0.03277851788802352 + -0.2322537030083748 + 0.1982227211646411 + -0.2272728848992447 + -0.03318808364409243 + 0.297722163180038 + 0.1312673666716315 + 0.02707837278671361 + -0.1045740404142386 + 0.06787272474274135 + -0.0177580833569292 + -0.05490839383191812 + 0.1308294886719442 + -0.2207755143605773 + -0.1089692820110456 + 0.04825438989315921 + 0.09779390536555653 + -0.159821320130119 + -0.1159093358272197 + 0.05504310471972555 + -0.04369590214089984 + 0.07073691346077766 + -0.2665016984645774 + 0.02388628555373233 + -0.1331219373728809 + -0.1315555893633195 + -0.06908019445383771 + 0.2312935793190567 + -0.08531872120563737 + 0.02223642415897086 + 0.001315907955975409 + -0.003219648225799025 + 0.1870041029706274 + 0.1245742096237773 + 0.007212315883091193 + 0.2933352247807992 + -0.1566204420992092 + -0.08010624272851696 + 0.1786967634108413 + -0.1574906964543311 + 0.1441132851146465 + -0.06408174708644622 + 0.0717139431529894 + 0.03420951895790216 + 0.1331460517005429 + 0.04490175496779899 + -0.1682940088864579 + -0.1606290462842259 + -0.1095605690760876 + 0.0703893083785119 + 0.1301886675064558 + -0.06285998139635339 + 0.1072014485263314 + 0.1864957025207911 + 0.1656476217731681 + -0.03771128064524416 + 0.05275133711277115 + -0.05914498255328498 + -0.2412207759451671 + -0.04341537955952204 + 0.09853843308378572 + 0.08483301958683054 + -0.02168065306972378 + -0.05806995455294194 + -0.1079272844064938 + -0.1402367825155833 + -0.2052195370357991 + -0.1461590008469454 + 0.1674809774632851 + -0.1171866023103899 + 0.1770773086824776 + 0.02092695476785725 + -0.09157510795679843 + 0.08314239556065293 + -0.01217193864140235 + 0.01153770504490583 + 0.3140648343578761 + 0.2396795677341494 + 0.2249844623340858 + -0.244831129540522 + 0.1053719321222459 + 0.09361168043526424 + -0.02266110585285825 + -0.06167914271045204 + -0.03705363258744244 + -0.005263490772896322 + -0.09384491064174344 + 0.03946683821921681 + 0.01845952648647741 + 0.06066962117487223 + -0.02945166347639823 + -0.004223972154107899 + -0.1428458864404036 + -0.08579148420848684 + -0.3255186696508054 + 0.04540112842836656 + -0.05576060017284517 + -0.01384273119247929 + -0.07305402602545237 + -0.100654644786767 + 0.005329844548711019 + 0.02934153184211075 + -0.06984474286547115 + -0.04122717181903108 + 0.03290419475050719 + -0.4133569367044335 + 0.06775182474313729 + 0.1772140735162707 + 0.003248483255291397 + 0.04296208909131485 + 0.3431333654275189 + -0.03871745538008486 + 0.1766783407641636 + 0.0460523110090707 + -0.07520341094887323 + 0.08284553027863532 + 0.1740913079788215 + 0.01809985546751373 + -0.1094076772147493 + -0.03925931024129927 + 0.1017545885000872 + 0.09301126508547274 + 0.01796674827291573 + -0.08422663634004003 + 0.1314579050325454 + 0.009934515128281765 + 0.04736214721307783 + 0.1611831029076925 + 0.07469134378121381 + -0.008688620866355658 + 0.04282709599317566 + 0.1323820885508907 + -0.1107229385527645 + -0.1133368256790011 + -0.0459486059883938 + 0.1114174586694786 + 0.26349350716653 + 0.09818252537678392 + 0.03504037872886116 + -0.1162312971726918 + -0.1591063880725286 + 0.1555748484065873 + -0.154247216803497 + 0.0490591323247089 + 0.0929430548766054 + 0.1178215250516526 + -0.1134350274363533 + 0.07244243910134429 + 0.03998721194228382 + 0.1052494456143171 + -0.04262946624192485 + -0.08725504193066186 + 0.06265232603509548 + -0.1557092102388964 + 0.1753979955966792 + -0.06733339913948581 + 0.08715931476376157 + 0.02948267836490326 + -0.008909144763984772 + 0.1563359655905267 + -0.05026344163091333 + -0.3099416532081774 + -0.02252695372927473 + -0.05322128241114864 + -0.2313971425581751 + -0.1376543196677307 + -0.08065248195315032 + -0.0335594557425421 + -0.1087889341658553 + 0.1941952195731843 + 0.27335991085888 + 0.03174973422505341 + 0.1087183032023318 + -0.07277191334214393 + 0.1455907995382223 + -0.2001838849645602 + 0.03320370387695018 + -0.06197912233764708 + 0.01410195340752804 + 0.01372864142911234 + 0.07664842345475986 + 0.03233615007575832 + 0.04381621891927816 + -0.09361364408696254 + 0.006565063126730873 + -0.02813253533513596 + -0.002449654378479011 + 0.2924301339635104 + 0.1279139857807472 + -0.1502568345185902 + -0.07645015982645979 + 0.09421012372930569 + 0.3553212819567743 + 0.2494348310081459 + 0.0275948225891571 + -0.1435876140693143 + -0.05424799028852052 + 0.2409457651046875 + -0.1426719295706738 + 0.1154469398619241 + -0.05369085059805818 + 0.01897320528268845 + 0.01275747864292193 + 0.003689019913332679 + 0.02827455430048977 + -0.07984699455104921 + -0.06797394061366296 + 0.1212564950450237 + -0.1960618137453715 + -0.09683425857490388 + 0.1625091151723048 + 0.05735260304386951 + 0.0649558780618292 + 0.05393729792221152 + 0.05771647975747233 + 0.112328277324155 + 0.2010842151124908 + 0.1299469560205206 + 0.04705999169372613 + -0.07344074375644771 + 0.1731101441377517 + -0.08521136720832667 + 0.03103926449628581 + -0.2369087256316569 + -0.4057361910769023 + -0.1802663568471768 + -0.06830016428428791 + 0.02065208732647386 + 0.1304358199585746 + 0.009291199244945198 + 0.03131300120451403 + 0.2614638361003256 + 0.05726215855315517 + 0.1008871314671699 + 0.0776934461461917 + 0.2411573591019756 + -0.108961076734261 + -0.03143384627224154 + -0.08869558332854235 + -0.02620386274025086 + -0.1944154308886958 + -0.1464571280866085 + -0.08211537452518618 + -0.04525100538866837 + -0.01480706021524014 + -0.02622405533125793 + -0.03222492058576161 + 0.05531493263417533 + -0.09536230584591553 + -0.2657933462823083 + 0.003511554192852637 + 0.1040045950633752 + -0.0643319807725756 + -0.02456055406858055 + -0.1527368084273734 + 0.2039156838377204 + -0.04614595459571332 + 0.1383953210780827 + 0.15335789427913 + -0.09469437658861783 + -0.06939368529485657 + 0.02259770448006768 + 0.09063562523011133 + -0.03506968044716959 + 0.004689551738990857 + 0.0701692225806361 + 0.1524524551345627 + -0.00887168264725475 + 0.0612795715519656 + -0.1880743639803473 + -0.03419202920347694 + -0.2205024044827757 + 0.04316044181250382 + -0.1860162859585104 + -0.2952115152104636 + -0.08086769540225973 + 0.1271400705169667 + 0.09997258260052364 + -0.1484255014522047 + -0.06001497231748486 + -0.2055772052697093 + -0.06461080274518102 + -0.1154168540652843 + 0.2450778606519572 + -0.09774093966489961 + 0.03361481812357046 + 0.1274484861655066 + 0.04658229224015976 + 0.1682097468429917 + 0.136374068518749 + -0.06650469470777762 + 0.1454777819236287 + -0.0157773352449335 + -0.09863551419750645 + 0.4622932525711828 + 0.04710157842102276 + -0.03443272187990695 + -0.2832439423713189 + 0.1638567961588143 + 0.09442389295231869 + -0.007576265363466159 + -0.2879655869659259 + -0.0743581323142373 + -0.05042343051430474 + -0.1172837493064219 + -0.02559801558175114 + -0.07067220311485925 + 0.1125519225973421 + 0.07585188970971808 + 0.2420419973543043 + 0.179652579607638 + -0.1280025305739423 + 0.06818308740058765 + 0.07556006179131504 + -0.1940808202141242 + 0.04345232351334239 + 0.112443249129403 + 0.0989908603263522 + 0.02088908872875778 + 0.05790370714827859 + -0.01796710156257132 + -0.2792180665172357 + -0.210693400008256 + 0.111017788230398 + -0.0298717163527407 + 0.003758143044481368 + 0.03771808997590925 + -0.07308416037773038 + 0.07385573875491853 + 0.2317103066600028 + 0.04775874399765781 + 0.0008162012429432146 + 0.1167119728324198 + 0.2494491214796501 + 0.03502285208264171 + -0.1993792192288653 + -0.02992864390518694 + -0.03988931355877789 + -0.04845462260168403 + -0.08525205846589816 + 0.06458784740877944 + -0.1457621300482446 + 0.2372288490763193 + 0.2315088860789077 + -0.02906439075567777 + 0.09043893831471891 + 0.06806004901408956 + 0.1773685381359586 + -0.1002895339525629 + -0.1030474940028186 + -0.06685135721556766 + -0.009494480748024404 + -0.08233077107660457 + -0.06795900382431448 + 0.01984187301448656 + 0.1879683707803882 + -0.03264058325964003 + -0.1029122265241363 + -0.02568932697075629 + -0.2521045791709349 + 0.04317657967759692 + -0.05645267796085152 + 0.2238174134328292 + 0.1057869088465305 + -0.1028237655007978 + 0.04697808684187352 + -0.02692511781227247 + 0.07514191727511906 + -0.0325372214288146 + -0.114105831706632 + -0.1332982644144468 + 0.143888682494877 + 0.1923741971777899 + -0.009441879578553006 + -0.05305916645584323 + 0.3655496397624907 + -0.1047726696649691 + 0.09839744252839218 + 0.146262029875463 + 0.04783809674776492 + -0.05961764261014981 + -0.2303543547302474 + 0.1239376438255468 + 0.0902998117749161 + 0.1882512706033346 + -0.06098355383884435 + 0.03492676899891604 + -0.1279398887896151 + 0.07494299689706893 + -0.06867091735070924 + -0.1011853585030417 + 0.002110145973569824 + 0.1122651892907851 + 0.2245176403570509 + -0.06151859448723768 + -0.1905807695250177 + -0.1042842346187136 + -0.06993332850885071 + 0.04984860043000781 + 0.04047400265423855 + -0.01068933422058112 + 0.04823808865646682 + -0.1243800732412288 + 0.2316511829482659 + -0.008037639587616455 + -0.1778516712913076 + -0.2052946682411498 + -0.1687083974501712 + 0.03459655001895804 + -0.006630064203240225 + 0.1006584019709 + -0.04244122159478375 + 0.08159497935877594 + -0.01266493479379308 + -0.0288792121905993 + 0.1682379198614404 + 0.008728001158971396 + -0.1555792526281528 + 0.1635304848911861 + 0.01630985404599713 + -0.05296878016437333 + -0.01537197781945606 + -0.1207389398644774 + 0.09168035008466739 + 0.2925462203322529 + -0.1598920960179509 + 0.1746087338012031 + -0.04144942997718663 + 0.02055106366848109 + -0.04187894692093149 + -0.1177700554574433 + -0.067864386769004 + 0.04982664374529477 + -0.03477383810396281 + -0.1026457900365856 + 0.02389394304207002 + 0.1574495591570526 + 0.09739512718297694 + 0.1106261083233014 + 0.00801404846251458 + 0.1613322442360942 + 0.08616735645223149 + 0.1859789764165273 + 0.2474742546739467 + 0.06291682520729272 + -0.2030437971549434 + -0.05382540471511167 + -0.03812255457064273 + -0.02457863077762059 + 0.1781307308649321 + -0.01237139654450955 + -0.00114844506680325 + -0.1298759640158143 + 0.05817115711263673 + -0.3530874584580207 + 0.1136046931567839 + 0.03309808390053976 + 0.08131867939377826 + 0.1831587802279089 + -0.2034076083246985 + 0.04731554699004937 + -0.02775319654121298 + -0.1410403927210198 + 0.06762738875729439 + -0.1061971942924593 + -0.05350723567508586 + 0.07649038651118326 + 0.08921996521851855 + 0.04791840793953057 + 0.2480402245018685 + 0.06247923214066559 + 0.1280832419886825 + 0.1330282338987272 + 0.06854235337126194 + -0.03975494973853664 + 0.02402641448972406 + 0.145413219878447 + -0.00350099405653656 + -0.09810997341003236 + -0.1500518919795678 + -0.275020134408748 + -0.07505396684635902 + -0.1457041606386233 + -0.3393187166056383 + 0.1331571973328037 + -0.110283055446299 + -0.02562766355709294 + -0.0558913701239514 + -0.0540756304549689 + 0.02139833868657917 + 0.2205169077130332 + -0.04415656578896279 + -0.1615604785746199 + 0.03657934722427986 + -0.09425250958089726 + -0.02845521308420071 + -0.08266720616518415 + -0.2489411019473962 + 0.01551150807894458 + -0.1277766426254786 + -0.1691337461890193 + -0.09273232958486907 + 0.0845434590416053 + -0.0817751520007895 + 0.04361955426464188 + -0.262435290409621 + 0.1442086180490096 + 0.07815467566285009 + -0.2562333574160348 + -0.2275846595756743 + 0.1486191045161695 + 0.2855672884338436 + -0.1398290720386017 + 0.1731883617890136 + 0.009957407779010814 + -0.09448514311850834 + -0.1593999127820855 + -0.03854423723202845 + 0.2118057062761691 + 0.01930063332334164 + 0.1506572182847392 + 0.2308755807189392 + 0.1442402790078226 + 0.0530624584100496 + 0.04252502304683763 + -0.1317695271211297 + -0.05924126515106762 + -0.1097744994715752 + 0.004630728843213914 + -0.106197543538807 + -0.0998591148670562 + -0.1604477184855824 + 0.2646560396434452 + 0.1480768751094904 + -0.05162166226015313 + 0.02309799163797649 + -0.2814022399810224 + -0.02969994659345677 + -0.1395323233630525 + -0.268298986889466 + 0.4146699577137405 + 0.1014612430879724 + 0.1821610284707323 + -0.03092092842970402 + 0.07234289713535821 + -0.01041232905007928 + -0.1474829460290751 + 0.03362189986808967 + 0.03201243006072946 + -0.06957364486403016 + 0.0899445395012064 + 0.1935554792783035 + -0.1199422743478855 + -0.06353686911752858 + 0.1364805514280732 + 0.05643413420523858 + 0.03690107874732951 + -0.3773551167868887 + 0.05649944329596363 + -0.07684561102210888 + 0.04350290182599659 + -0.07919882384150727 + -0.2039564331696269 + 0.05629593168269784 + -0.0298110525392648 + 0.1717338301460992 + -0.01785708941003036 + -0.2024444721638224 + -0.07202577012263808 + 0.07234709133240455 + 0.06584590085102029 + -0.1078776389011856 + 0.1029176823718753 + 0.06760606622634731 + 0.05016141636702857 + -0.00339974708292407 + -0.03646702814256569 + -0.04890538611847352 + -0.009125287635034774 + 0.05146855159228438 + -0.1333717654033707 + 0.08210873107533997 + 0.29076471220691 + -0.2153016200718147 + -0.0584331067687738 + 0.1027377358039736 + 0.05707947341335337 + 0.1667090660184277 + 0.1976291448841175 + 0.02705729925436348 + 0.01796950700497731 + 0.06239382005319734 + -0.05082587991023677 + 0.09761408457778654 + -0.08940644377316814 + -0.06202291503023948 + -0.07776493497605269 + -0.1336187903269319 + -0.3230132731727937 + 0.2026037072666919 + 0.06478741284224945 + -0.007670666588370619 + 0.02412129735770062 + 0.1549891824772819 + -0.02400206066288015 + -0.02870356578221772 + 0.2000413014906103 + 0.08609323070443986 + -0.1638678325480539 + 0.01214314996945172 + 0.07249614106737805 + 0.1439697415499205 + -0.01725091313445289 + -0.1469376673305392 + 0.02595477068778226 + 0.0656249719102938 + 0.08198805995748196 + 0.134772323868445 + 0.01101929296878628 + 0.002542188397544281 + -0.08349254207437565 + 0.1639297528158151 + -0.3768610749072907 + 0.1193802020527624 + -0.7697569130806157 + -0.2212924141519562 + -0.1681963510971431 + -0.3145464746558496 + 0.06697730222334126 + -0.03112173839743644 + 0.02307491489955696 + 0.1779478861056873 + -0.1247043537880247 + 0.1007967404580479 + 0.2357077424255827 + 0.06232940371195738 + -0.2778913971415855 + -0.2392497454953789 + 0.08819940141049225 + 0.03000924825976448 + 0.332884041643997 + -0.1303595676940465 + 0.03196268480698171 + -0.1167470328550719 + 0.1892232447370581 + -0.09112310014241388 + 0.1042936618050788 + -0.2723908567928376 + -0.007807977398082571 + 0.2543584458207669 + 0.04754557711456058 + -0.02702586450417269 + -0.11247871762982 + -0.09908603805634476 + 0.1788009668591205 + -0.1479500846715779 + -0.1273106699193646 + 0.01493238263591523 + 0.006088374554609633 + 0.20848851010708 + 0.02960787768672649 + -0.1871474654099734 + -0.09261442327916931 + 0.112615633171938 + -0.0477977622372065 + -0.06855526883756495 + 0.09516219703305855 + -0.03771138000669634 + 0.06536359649796689 + -0.213911711083961 + -0.0184447990250914 + -0.1661792336858582 + 0.02508859994982515 + 0.1692517069104558 + 0.2603517069755765 + -0.1611989560822039 + -0.1185667809432909 + 0.08500005984630972 + -0.1794990547496751 + 0.1082623427790162 + 0.2439491750351128 + 0.1222696381705514 + 0.1972043484281278 + -0.1028242609241676 + -0.01791131640789705 + 0.09985342344774374 + -0.2370203511062225 + 0.1084863755220742 + 0.1243641419869446 + 0.004428783435230674 + 0.1166853829263854 + 0.0006417599748490489 + 0.07671629582011849 + 0.3423576057170364 + -0.1286038917737745 + 0.01098050492101829 + 0.1378661619571264 + 0.03998660684459197 + -0.01005031263122967 + 0.1086828262986002 + -0.01727507920194267 + -0.06986219185448164 + -0.01427371425125049 + 0.0885045711825615 + 0.009883819379971704 + 0.1894430080463225 + 0.03484655823368423 + 0.214884581387276 + -0.07130934093027447 + -0.04340437887562161 + -0.2022571389717478 + -0.02501150279020167 + -0.01278745513540494 + 0.06716704213823628 + 0.1851014372250321 + -0.194051534415858 + 0.1788158973775606 + 0.03188963064137908 + -0.08253812956052718 + -0.06170568993328969 + -0.05737790184588787 + 0.03885178012826314 + -0.01354704450405351 + -0.05551526757755507 + 0.0007761519328859751 + 0.2757262930258098 + 0.1703222680758462 + 0.03583533982022052 + -0.1184735909773455 + -0.2484053745821439 + -0.08398857949189971 + 0.1018498084782536 + 0.06636905895411564 + 0.1124592143743815 + -0.1347358818391486 + 0.1518183767349677 + -0.03562442174682971 + 0.08418917643700233 + -0.02920869049669517 + -0.1745529973124222 + 0.1037633610308533 + -0.06235644863091044 + -0.01196390537163998 + 0.2731464249223822 + -0.03804965905807817 + -0.06399023174599729 + 0.03547330035402781 + -0.01804496861815282 + -0.1024977563933929 + -0.04501010768300148 + -0.04910453547920961 + -0.01728294054364678 + 0.1572386315096017 + -0.06734885497082059 + 0.1443934100694797 + -0.1436615543943069 + -0.09466828377217448 + -0.004330153042636131 + 0.1913010148017029 + -0.1368754415116969 + -0.00208609509175319 + -0.1312275937571549 + 0.07444739943629684 + -0.2329053404501217 + -0.2353707836953204 + -0.4670382295590909 + 0.1676718329911781 + 0.1256197734101599 + -0.1527130733158328 + 0.1394342797512396 + 0.005729875436846226 + 0.007173844000127672 + -0.03541315470374997 + 0.147206034049565 + 0.272633085022892 + 0.01253635783119945 + 0.08281616319501042 + 0.117315213179572 + 0.106769320571199 + 0.07978772367351653 + -0.05038937449415107 + 0.0364650804498464 + -0.03399044141345221 + 0.008989999415654336 + -0.06135875114513663 + 0.03701824757004867 + 0.08834510093795316 + -0.1278252370645362 + 0.1574450128407891 + 0.1655971666411339 + 0.01154446735174964 + 0.02891216529006158 + -0.1510320590519443 + 0.05204112594114344 + -0.07593744680166088 + -0.4138633883342974 + 0.2971610789853015 + 0.1032389457227845 + 0.042722708165842 + -0.07398693402250441 + 0.04680673326062725 + -0.1550704335285432 + -0.02835355382795042 + 0.001013562389351253 + -0.03415613998520712 + 0.1035506496875199 + 0.009702094458653499 + -0.03053279813549682 + 0.01911176807061997 + 0.2017057983970884 + 0.1156356413096757 + -0.1595455041757185 + 0.09890136233921518 + -0.1778554275110646 + -0.001807292015045894 + -0.1906967933769538 + -0.07257211703374573 + -0.06248519921819782 + -0.01249856873485695 + 0.09398110471902847 + -0.02160325627512833 + 0.1245407646495057 + -0.05232644551298546 + -0.1790765773523827 + -0.01897172327316724 + -0.01962115402213288 + 0.2119706354113583 + -0.151308906841208 + 0.03418825523820215 + 0.1537911475109066 + -0.03595210444858842 + -0.08491740445548025 + 0.0327406120855941 + 0.1256431957379078 + 0.08999861349306743 + 0.08760907484101546 + -0.1039145574117216 + 0.06398995044988803 + 0.4298587134553199 + -0.06102954219851842 + -0.1014616362107472 + 0.07713828412731696 + -0.1444581254181776 + 0.2307687752129999 + 0.2334921997037168 + -0.05998435740010866 + 0.07889161262700368 + 0.003578566114233683 + 0.06149617990064773 + 0.1811831206069739 + 0.08757078068453107 + 0.03400379089270179 + -0.131330229422718 + -0.1777631994598496 + -0.3290570890762421 + -0.02835966373002344 + 0.03524444326120029 + -0.1080349870804105 + -0.01195764247083099 + 0.04683810773614416 + -0.02230029202487139 + 0.1169618632296458 + -0.08851404824049508 + 0.04255511064689352 + -0.1562474583322839 + -0.08122905722240509 + -0.1704179301914067 + 0.08537830096966534 + -0.009797310754328685 + 0.1414731548451054 + 0.04627016369924405 + 0.1377370974472886 + 0.2636392257951558 + -0.2817031995233829 + 0.09831748910435606 + -0.06839020807394663 + 0.1280549372926579 + 0.148760866245911 + 0.01898582240542632 + 0.0933142153584746 + -0.05057622296644462 + -0.2832701052078901 + -0.1028754888172324 + 0.1403578542345698 + -0.1833699674137213 + 0.02141267876055514 + -0.2998055512704632 + -0.06539238256887613 + 0.02530649266748932 + 0.06850147636661247 + -0.001889913437682705 + -0.05283586200400071 + 0.008108253139624917 + 0.08240507879696403 + 0.04560331658201312 + -0.0699857999776398 + 0.1086942793177416 + -0.04494937655217514 + 0.009100631658522327 + -0.07290206367182554 + 0.1438805512608022 + -0.04704044584113247 + -0.1711495592485757 + -0.1122872098904535 + 0.01936821183861987 + 0.06438997344154014 + 0.04255883302612039 + 0.00973666537978766 + 0.04875120868678354 + 0.01188379936070664 + 0.1177921661224317 + 0.1475238640848043 + -0.1295175158050947 + -0.06133022169748133 + 0.2547427913807691 + 0.05325537204173097 + 0.05816878790942419 + 0.07433569920857755 + 0.140841277859727 + 0.08534630320085594 + -0.03993419415585034 + 0.07343852091749987 + 0.1447256254233307 + -0.05922094075484226 + 0.06351622340299432 + -0.2623012473648039 + 0.03452007042708084 + -0.1016908036134709 + -0.001857342774820718 + 0.08004858115146685 + 0.2262818666995441 + -0.06603100555720481 + -0.2053596158294931 + 0.05147830504666341 + -0.1911422727890306 + -0.09706700280155754 + 0.05689820173409721 + 0.4055416755968649 + -0.06045015747968319 + -0.07215582679990599 + 0.09047104314226406 + 0.08792909000318049 + -0.1384239188079479 + -0.07526870151890001 + 0.05430573940157028 + -0.03061862974998544 + 0.1920483112105993 + 0.01361571257424987 + -0.2022986330679549 + 0.08576621131137273 + -0.1006769503700991 + -0.04829909267755558 + 0.07445329021491819 + -0.05785914769218926 + -0.000288026838702963 + -0.06039200903907745 + 0.04740370916698566 + -0.09210572312764646 + -0.008982897615944547 + 0.2089714371613931 + 0.003802995174447648 + 0.1282832576030806 + 0.07085126629284354 + 0.2575779573336598 + -0.003245695368985666 + -0.04645043743831927 + -0.03592711768097116 + -0.01501835018022073 + 0.01222520233100322 + 0.05324069261113746 + -0.007630051770320241 + -0.06519217637440303 + 0.2772122564727599 + 0.05421092793840426 + -0.1795493423378846 + -0.1043030228048571 + -0.2096157493654643 + 0.03161970429654114 + -0.162957657579994 + -0.2029210829360478 + -0.07873777224210178 + 0.01549336902258435 + 0.1195119318163313 + 0.1628895010184224 + -0.2331677475272382 + -0.1179024507595966 + -0.06601264399183283 + 0.01218647724486012 + 0.1246464607113467 + 0.04651012132072902 + -0.09122572593482157 + 0.1304489894385491 + 0.02460312741297827 + 0.1498139448125036 + 0.1294024976467686 + 0.002203916297196569 + 0.01400735487612577 + -0.06904451846888261 + 0.02244753505164843 + -0.1572124025941077 + 0.1379598358264871 + -0.07694981373413404 + 0.001838132802904508 + 0.03666987814968007 + -0.0410467125186896 + 0.06264110288488313 + 0.04978779246132818 + 0.2266903342914401 + 0.1355720700670011 + 0.01580792019937535 + 0.3992858367294341 + -0.01517818093267168 + -0.05642782056978031 + 0.04389038142601238 + 0.2769661938885635 + -0.2094644741193975 + -0.01666146892767501 + -0.05902280139308708 + -0.03686782691408207 + -0.1997312222186776 + -0.09509481309887594 + -0.1845015267858572 + 0.06017821034235248 + 0.0803345684071237 + -0.2231198267850516 + 0.1196152587195683 + 0.0006534887741532187 + 0.0693280567312691 + -0.0999848616946544 + 0.04983856620229732 + 0.1166291413501656 + 0.01231080972420872 + -0.1553107478114333 + 0.05633787454245718 + 0.0131816237445624 + 0.1469588545322484 + 0.004650806424363286 + 0.08171864806490213 + 0.007667240734114789 + -0.2769519987192213 + -0.07068737420795315 + -0.01335151611115145 + 0.07934103151738113 + -0.05277150963284991 + -0.2204514564377206 + 0.06770385071557219 + 0.01349377337296595 + 0.06724870882152342 + -0.07321971693821221 + 0.0689815566096212 + -0.06556822853459073 + -0.3405769780780462 + -0.2079202715642693 + 0.06874620651005929 + 0.1014448664188468 + -0.0899575247326684 + -0.008633996238676197 + -0.1318760825377482 + 0.0537456516068722 + 0.04143429301499196 + 0.05769910880675788 + -0.02517423883738 + -0.0243614922091839 + -0.09878680065472323 + -0.1673317736328157 + 0.06266832909058168 + 0.1621691492551542 + -0.1143393628213833 + -0.05096783041597443 + -0.0329197429046467 + -0.0235137527585709 + -0.152886255965112 + 0.05093560464103159 + 0.0413186428856004 + -0.1118916283589024 + -0.1973663614814243 + -0.04348765532040831 + 0.06031361729075244 + -0.05149962671389304 + -0.1186287422520261 + 0.07882155850965274 + 0.05028301695623184 + 0.1805170097025446 + -0.03834334654557187 + 0.008261548203595932 + 0.1198297017706722 + -0.1208120540244246 + -0.06950348113101155 + 0.1907045386237932 + 0.08165601937573704 + -0.01614123998677435 + 0.117706334185299 + -0.1244341417566289 + 0.03239572909980223 + 0.2268711577146954 + 0.03526082219974716 + -0.05546513529591963 + 0.05958464319749743 + -0.1265909351671086 + 0.09675752816798573 + -0.1207550094341743 + 0.09779956939124441 + 0.08801758535309609 + 0.01280399571287237 + 0.1082388938336093 + 0.03515949888262818 + 0.04812613344167038 + -0.004193939645691374 + 0.08946323725090613 + -0.09631050033452093 + 0.3075350177834638 + -0.06634672135964825 + 0.07925227109529463 + -0.1409078912558518 + 0.05056851836101016 + -0.01700815625902306 + -0.06037943269559536 + 0.09892857925799212 + 0.08207875678191826 + 0.0401805078370504 + -0.04691411048033799 + -0.1662293308415775 + -0.2386409089095987 + 0.1586092106306007 + -0.0204356756327099 + 0.2627466381613962 + -0.1157412604526542 + -0.03923621018256393 + 0.3193006336495912 + -0.01181507447535234 + 0.1254963820836255 + -0.04696239711554804 + 0.2112234161247342 + 0.08163203374064897 + 0.3712691614291372 + 0.2283796358644019 + 0.2420889510666089 + -0.281673795428583 + -0.1389834210322841 + 0.2943637510606202 + -0.1975271758184561 + 0.1195817368993112 + -0.2066886502902928 + 0.1033015872255916 + 0.1029312706874491 + -0.02355045691314823 + -0.03711032362622817 + -0.049928013128906 + 0.0146609823226943 + 0.1068268367986153 + -0.005238915606817294 + -0.04449246861487063 + 0.0739165699188737 + 0.1175015099835593 + -0.0243198957171463 + 0.07690788118031312 + 0.1096078461382219 + 0.05853528842874703 + -0.1919779200916936 + -0.05562009028453184 + -0.03235072832237598 + -0.09081991578068289 + 0.1105893907789839 + 0.00280376974543959 + -0.07294169392772441 + 0.0593325025186879 + -0.0829750906869218 + 0.2424132404060261 + -0.04390007976447648 + -0.0873205133527018 + 0.1913256250076217 + -0.05789972447599219 + 0.1191838521977546 + 0.07900534964962966 + 0.1129964413566027 + 0.03845314612416371 + -0.01317128353652406 + -0.02754672704586516 + 0.04604311801172246 + -0.02687915964511522 + 0.1191444452592128 + -0.2392759431145069 + 0.01014355816765817 + 0.0580615715529177 + 0.0914704018910612 + -0.008884776013316038 + -0.04174903019054066 + 0.14955696141056 + 0.1336423278175688 + 0.02123406414716683 + -0.1375520801272396 + -0.1887516837003186 + 0.05191888771528524 + 0.2925449608997491 + 0.03245073533332654 + 0.02192667445428681 + 0.1404058648788435 + -0.02028972204692782 + -0.04913767326933603 + -0.002364782444934244 + 0.00965292158421107 + -0.04144962060783889 + 0.09228770761422608 + 0.04112390328947663 + -0.3967713971507376 + -0.03255896326177396 + -0.09554414475173044 + -0.05747590975060092 + -0.05546432616814327 + -0.000166187772064942 + 0.1062606880514689 + -0.01455756280987187 + 0.08262341961431828 + -0.219871104445319 + 0.03597020818609064 + 0.2315650637310843 + -0.03958668798802647 + 0.07855633440888411 + 0.1030849307433538 + 0.006127776655955027 + -0.03728892565704994 + -0.07241346010985282 + -0.08780590558102311 + -0.01740091800666538 + 0.06585768438947309 + -0.06094450606352605 + -0.09395148275873738 + 0.1026817079466833 + 0.1932802332254911 + 0.162764433792275 + -0.01324235558117182 + -0.2206420718282719 + 0.009920626486896266 + 0.006057614362890605 + -0.1411360490903299 + -0.2164550302726913 + -0.06939873057915501 + -0.498731101783119 + -0.00385814543924401 + 0.2153053789400234 + -0.1669108972524112 + -0.03539562399349915 + -0.1272513348545094 + -0.04215578131798401 + 0.2145207734956126 + 0.1331724101917932 + -0.1098188629910101 + -0.02168924754782288 + -0.1106534730987053 + 0.1085657570585296 + 0.1251350262479071 + 0.05778852887854908 + -0.04742373437661727 + 0.01797717897646522 + 0.01645073086220431 + 0.2664561481422336 + -0.008392111472630187 + -0.04528896930336532 + -0.00216995855390202 + -0.03916490066317626 + 0.02198220012055105 + 0.05555817935154898 + 0.07599306511099609 + 0.1362888427705322 + 0.1554237734967745 + -0.04551202934879932 + 0.1069293564908843 + 0.1180088398692217 + -0.1133149481407102 + 0.08121494920599147 + 0.2646036558026292 + -0.2680881726094901 + -0.1947311428580881 + 0.005697175228141779 + -0.024058085666542 + -0.09151138411650346 + 0.2790377689348492 + 0.00143556469283001 + -0.01545180402031711 + -0.1926163179636097 + -0.07773657840772526 + 0.03577573808018113 + -0.04838235032545117 + 0.03068462739239929 + -0.1387770103835139 + 0.01909701250847535 + 0.01736687926195046 + 0.01883761066448333 + -0.1129357845163832 + 0.09855311989182682 + 0.004589081249278285 + 0.18725128783944 + 0.01550393360272544 + 0.1093913651796013 + 0.02628663360875518 + -0.03829388673206289 + -0.105746267779198 + -0.142118170935968 + 0.05449591018541769 + -0.151018406625868 + -0.153723790640134 + -0.008451157597419039 + 0.08925480787582508 + 0.04699635773247333 + -0.07590012352052174 + 0.06014588467749803 + -0.03237137826702115 + -0.3183451703992329 + 0.0875859134231752 + 0.08964738038496677 + 0.2821280918359231 + 0.005662018097984336 + 0.03056095026899291 + -0.1882400506327246 + -0.08449772351404176 + 0.07991338212418417 + -0.07326873742972478 + -0.1863414254955279 + -0.01319297352559068 + -0.01449668152337194 + -0.1261539684963731 + -0.1883329468916585 + 0.1423233693263666 + -0.08255587111893474 + -0.1141101550114962 + 0.03695196019278594 + -0.04072939643458205 + -0.1816130657213404 + 0.08586036121206912 + 0.05124622044257115 + -0.2251892885789057 + -0.4797212360798791 + -0.05549447976051809 + -0.1733223006890926 + -0.02810359722888719 + 0.04877735500991873 + -0.191666458982011 + 0.05942958732370112 + 0.1671513379397107 + 0.1094287220875946 + 0.1247558320833959 + -0.06563015056961696 + -0.05701115550338574 + -0.03552623205876849 + 0.02987451744304551 + -0.171299712843539 + 0.1255319518586041 + 0.177864398040107 + -0.0907314208486666 + 0.07818614115408005 + -0.02216558399800002 + -0.1202248200307474 + -0.03927548598722567 + -0.06580683250926828 + 0.04584251582050356 + 0.2291711708987619 + -0.2292464328148839 + 0.005712488594544227 + 0.001411987182642534 + 0.1437168015077329 + 0.2207250968630461 + -0.03040152824312825 + -0.09163135049325133 + -0.05553346446533728 + 0.2893526675049227 + -0.04377551385726801 + 0.2571736983640531 + 0.0315288253194958 + 0.07015499073129612 + -0.05599623927470815 + 0.04752956918115923 + 0.1600765040849279 + -0.005855937437852521 + 0.1274030475061361 + 0.1664775049021864 + 0.01529660960014022 + -0.06400075394324004 + 0.02249443258044355 + 0.007313269269809203 + 0.06226120378549171 + -0.06515344424510049 + 0.1568628708771108 + -0.1460478268205407 + 0.003509720329546019 + 0.3147860634711218 + 0.1067427958971875 + -0.01232217623658509 + -0.117080571480174 + 0.1114377531566743 + 0.02986809717666046 + 0.2917139776371681 + 0.1488158375149453 + -0.1020770229650464 + -0.2724511974927713 + -0.06846503524543952 + -0.1216571076104225 + -0.1563323908332596 + 0.2482538139343893 + -0.05330376867448976 + 0.04077766875038313 + 0.1289781526280537 + -0.01950364386916388 + -0.03131871028591678 + -0.02393909763780365 + -0.04003190736139422 + 0.09177588796181167 + -0.03135089689512027 + 0.03817521828212919 + 0.1550290015856702 + 0.1491135104682224 + -0.05776170485294529 + -0.0606283708625731 + 0.02420577837027465 + 0.1096046698416483 + -0.06832501046485764 + -0.06025481187237652 + -0.05713198949008493 + -0.1115617925067333 + 0.01732638989195593 + -0.05138089165158981 + -0.1726948431105822 + 0.1561199121907351 + -0.09347701987379298 + 0.07120136997733857 + -0.04899064095725596 + 0.01018054910601599 + 0.1420625571236766 + -0.02194993127520828 + 0.165452099447372 + -0.01742395167695984 + -0.05992497363119213 + 0.1033815810803336 + -0.05653441988631364 + -0.0388155111464341 + -0.0166015167043805 + 0.0274138125074293 + 0.101805240598185 + -0.07729067099646124 + -0.06188927731361168 + -0.0100185248292066 + 0.03460900093152912 + 0.1226685406386579 + -0.001757099748671331 + -0.08839696288114754 + 0.1588837040266128 + 0.163601062828788 + -0.13826633220042 + -0.08152173912197842 + 0.008506746394785361 + 0.07042556131263193 + -0.1828657545808618 + -0.03848807844263183 + 0.2606417611079284 + -0.01265122240910012 + -0.09397630781127818 + -0.09748902091685237 + 0.105866264912152 + 0.01896539015218655 + 0.03727952419280388 + 0.1356579535941467 + -0.2376481909952 + -0.002655511764697968 + -0.1743034157769036 + -0.03230914849792802 + -0.04919283048200387 + 0.04992690302660464 + -0.1289717379605334 + 0.00102616320028599 + 0.03478821231647943 + -0.1769792199015237 + 0.05763456781085124 + -0.03671818539191991 + 0.1008802439141509 + 0.1136148027650005 + -0.002567505373993753 + -0.2756069303559292 + -0.158115294759348 + -0.1086499956201196 + 0.002846788351640035 + -0.1189305369308229 + 0.0311792838299531 + -0.2239770597758744 + -0.08231036079318614 + 0.08862385163541975 + 0.131008945252178 + 0.1907787404319429 + 0.2709292772826193 + -0.08307084287653484 + 0.03446911300784438 + 0.01750728010709182 + 0.05835275312271333 + -0.08604719696999655 + 0.05547809569775107 + -0.2553890780051052 + 0.02715648753903925 + 0.1507507653991545 + 0.0519486834894145 + -0.0210808836261286 + 0.03290650143910099 + -0.1270844254729972 + 0.1132300562737093 + 0.04159665516818557 + -0.1948375096323234 + 0.05739364360134825 + 0.04914049978626839 + -0.02422684163367515 + 0.2950433175222979 + 0.1519390042565463 + -0.06276568150556379 + -0.09561077032176436 + -0.0008378532471674976 + -0.1806188062236245 + -0.2420778639017236 + 0.06189512960544813 + -0.03872342988893834 + 0.2508174006510015 + 0.1248760017255552 + -0.1466699934890679 + 0.06194452024505161 + 0.07994076107156113 + 0.1541741990563387 + -0.008523247745018094 + -0.3862841820194676 + 0.06513823835110087 + 0.06359201764578154 + -0.0009936793314582546 + 0.2027632786253278 + -0.0827394422553194 + -0.3187135152576908 + 0.04662790662305236 + -0.01161450013403172 + -0.02961184580446037 + 0.2670706588229759 + 0.05214539555352883 + -0.1203018171547773 + -0.4478927277556519 + 0.1427811915174739 + -0.0009452916897276462 + -0.05958411841878353 + 0.03568905427264147 + 0.1088453123567649 + -0.0868523306888092 + -0.01843269790782425 + 0.02669644607712607 + 0.1368932942382582 + 0.03779970347539997 + 0.02211521663639291 + -0.08950440177402666 + -0.07478127170514788 + 0.07233690342985652 + 0.02634823503006173 + 0.1406981381324208 + -0.2896216362595403 + -0.1121983138388147 + 0.07196330086151316 + -0.1553042879140343 + 0.03637390451718276 + -0.05687159695765016 + 0.06919151073825189 + -0.01805904709167047 + -0.01148728056394477 + 0.1091348561167036 + 0.006320162599893106 + -0.2796085243257688 + 0.04739100273532246 + 0.09121740265040824 + 0.02640660763106167 + 0.1243318128016849 + 0.0678073515026652 + -0.01969988734011586 + -0.1169717251247893 + 0.09389876178033754 + -0.1723059167997276 + -0.03750938125555992 + -0.05872270975314106 + -0.06340521882151837 + -0.1344028859715276 + -0.1588560293136797 + -0.1688707989086347 + -0.1257175256489785 + -0.125088715520732 + 0.2054866846531306 + -0.01506271934864957 + -0.1193881940972365 + 0.006854672134935615 + 0.04752726548117205 + 0.1124313047487734 + -0.2345716043131754 + -0.0966784526190799 + -0.07068464232571015 + 0.01736857233411952 + 0.04488167006610325 + -0.2843837732643927 + 0.10716574280311 + 0.1666004751499099 + 0.2857988321304801 + 0.122947875889353 + -0.08663222981928188 + 0.0212658468879969 + -0.003613203808198238 + -0.09128479640783342 + -0.2531883278119825 + 0.1815634810104498 + 0.08845489272367121 + -0.05233137768136104 + 0.08031762182304369 + -0.2155777146411779 + -0.2564823595474058 + -0.03019130441808567 + -0.1797136818846594 + 0.05377877052887539 + 0.1096448138915206 + -0.1479548314371374 + -0.2690653689962727 + -0.04255533440371613 + 0.07790825620708147 + 0.3199944979618799 + -0.08049724751558474 + 0.139398263929424 + -0.03513301979550565 + 0.1557230323367141 + -0.1043800105403567 + -0.04915709973821722 + 0.1740392832053469 + 0.07850578662337659 + 0.06900135804453329 + 0.1543174396321019 + 0.1913021203470564 + 0.03248262135533719 + 0.1362352004509483 + 0.03820012662259802 + 0.02465376305200654 + -0.07973176671490013 + 0.06660671848250377 + 0.18871219108177 + -0.008093631404408198 + -0.1767246417538758 + 0.00990266015180156 + -0.07132583087173691 + 0.02628871489469766 + -0.01151204088869364 + 0.3209454112733626 + -0.01572949438450685 + -0.1179416333477361 + 0.02767486872290684 + -0.003196235972921697 + -0.2018400719502092 + -0.1443658218393715 + 0.1409700805900654 + -0.1374062844011678 + 0.1566387766450519 + -0.01464142325283152 + -0.09386910081568539 + 0.1940871551473544 + -0.0009229305722659523 + -0.1003453469074656 + 0.08707272424241898 + -0.04084866700580461 + -0.00835848653063914 + 0.1374031742323946 + -0.05941076295697365 + -0.05361274680393424 + 0.06005774690231313 + -0.08728264413619945 + -0.03182871408833136 + 0.07761623662150324 + -0.005465534469940489 + -0.1435986443157352 + 0.2229362210983785 + 0.165694452920798 + -0.09733483826165971 + -0.06192171203911068 + -0.01201138599168869 + -0.241464183207144 + 0.01447397517722392 + -0.1580508339638638 + 0.1239975988161607 + 0.01318763966961383 + -0.02318521075282481 + 0.1253227011275004 + -0.09051730063913441 + 0.1010992941034518 + 0.07236374335157782 + -0.06829558579670918 + 0.08802095769461238 + 0.02222150657255103 + -0.1240027586042427 + -0.1127318578300772 + 0.01058998788801809 + 0.09129799024348864 + 0.08406216402634781 + 0.01469513470310243 + -0.09377037590621057 + -0.02957921396339794 + -0.02224655259628815 + -0.1256856814296717 + 0.0327859115036057 + 0.01735739917724188 + 0.2321654126178073 + -0.05301387703579736 + 0.02086166570938919 + 0.1808990770867712 + -0.01100092518093565 + 0.1254107013013275 + 0.07712432562303929 + -0.1846333616553162 + 0.0354631792700261 + -0.1237949044698444 + 0.267900287597566 + 0.02569258517592024 + -0.04495669809550676 + -0.1168890230323697 + 0.0336975646046045 + 0.02125973110491677 + -0.02677683817964055 + 0.1197209867783265 + -0.0777858807226266 + -0.02425547448365667 + -0.08487292490805882 + 0.06291808994433309 + -0.02204340304934895 + 0.02377435051419018 + -0.1718773573170014 + -0.1011571579988193 + -0.1208029255107849 + -0.1441164927563105 + -0.04633424809550369 + -0.1422415093881239 + 0.2088533311413101 + -0.001853172596141906 + -0.1295936882431212 + -0.1282184353297419 + -0.1794144878161049 + -0.2040305688976426 + 0.1399649813297814 + -0.10764262620441 + 0.0616301297066474 + -0.1474197011387816 + -0.05050426102121119 + 0.1653477333539644 + 0.06068948659719262 + -0.05325459514810765 + 0.1373242105620577 + 0.03880137337106698 + 0.06017715543512947 + 0.06211813928644649 + -0.04191313812532114 + -0.04513341992023757 + 0.01914286643644276 + -0.04438971983871555 + 0.1387577841756764 + 0.05386357276079355 + 0.1042718732060936 + -0.07513626164669096 + 0.1786960028553379 + -0.05637216233733611 + -0.03720214170877462 + -0.1774340291717748 + -0.2549011743869734 + 0.186879844725118 + 0.2833063725183637 + -0.01880086739296004 + 0.1769374720509577 + 0.004564930889063233 + -0.05798972499647807 + -0.2747641741293661 + 0.027553184454707 + 0.2632412184052024 + -0.1095551353914822 + 0.06916048702527024 + 0.03080355376703287 + 0.2165981712802113 + 0.1890893856843088 + -0.08659995312896483 + 0.1069192157133039 + 0.0454950752455283 + 0.14187715557712 + 0.100672848815481 + -0.124773924250272 + -0.05335187514446071 + 0.1547592109188055 + 0.002641240342700039 + 0.1258711227814993 + 0.1206538733123445 + -0.135791533512724 + -0.130918815644207 + -0.05396861570570471 + -0.09140332872931331 + 0.09794058035021644 + 0.1588423831952299 + -0.1616346066767531 + -0.03167509234642521 + 0.2413978277122087 + 0.07297159339659552 + -0.003991980625359775 + -0.01341487228926374 + 0.1968283025420433 + -0.1106224029092038 + -0.02915201476535762 + 0.01299576259906967 + 0.1763479829281023 + 0.02034320445669416 + -0.007975760651902569 + -0.1878436437209434 + -0.0511284052070836 + -0.2054486303338899 + 0.08939311648359854 + 0.1069566349676425 + -0.3163184448636494 + 0.06701973428191561 + 0.01615250637797392 + 0.1795215061720997 + 0.02017711076221559 + -0.3561757064215255 + 0.03738435948083851 + -0.06283102722927891 + 0.1113950871495966 + 0.1520074264787128 + -0.05117322488552872 + -0.5240923053401126 + -0.04551984233766806 + 0.0596401451452126 + -0.2693136769181011 + 0.0703840776719498 + -0.09642522868000397 + 0.03163871728561705 + -0.04684419890810169 + 0.1078803552979049 + 0.01765144204601502 + 0.01842808628453179 + -0.2247013264156105 + -0.1572500241274349 + -0.1543378466013791 + 0.08844108358348482 + -0.2226388530497707 + -0.00802841258335605 + -0.1282277729831008 + 0.06727365881224892 + 0.01015621985250618 + -0.1004970234627534 + 0.102732150328305 + 0.1667404221737363 + 0.1832359281510589 + 0.1395964845806093 + -0.193799724903005 + 0.0191596749759875 + -0.0583700053589912 + -0.04116152622862413 + -0.08204498601953146 + 0.1714138796188239 + 0.1756244579872559 + 0.0390069765786883 + 0.08129445383792273 + -0.05658080254966814 + 0.04682762892287125 + -0.09957164218093659 + -0.05143646723972818 + -0.0480872450150412 + -0.01121554980364516 + -0.05096509640375396 + -0.01891053018629413 + 0.1746410924551564 + -0.1545065355810867 + -0.2141290021524509 + -0.04098056720418834 + -0.09707855006958718 + -0.01746835336172641 + -0.05827000757328446 + -0.06903569742387033 + -0.2576319419162038 + 0.0556139976498211 + 0.01293602538646877 + 0.3203057499851356 + 0.0727244748608836 + 0.2165980582221478 + -0.05750323110572632 + -0.06969582175803714 + -0.03590660607489582 + -0.2687061807209369 + 0.07258616839256866 + 0.2460848343887318 + 0.06489755354914239 + 0.08224910815883786 + 0.03288801465840412 + 0.01926730455644425 + 0.118500161428956 + 0.213596783357284 + -0.1274323690677871 + 0.04630213557499899 + -0.01416508956449309 + 0.1685802397578535 + 0.04117581547460621 + -0.1347008843688866 + -0.1925124798927196 + -0.02819143318336916 + -0.1353145214126829 + 0.01537443611510884 + 0.04182514849884943 + -0.02488285487230305 + -0.07523371621282608 + 0.0456453497418188 + 0.02320659688479692 + -0.09184485017807738 + -0.1021420570691875 + -0.09019704903516369 + -0.1115790792593659 + 0.06726113707953835 + -0.09485300922229126 + 0.08202262147375204 + -0.1951874480726342 + 0.01751795456052687 + -0.1731541700471953 + -0.04642163512287122 + -0.1274507602620129 + 0.02694469481270243 + 0.2510538147171613 + -0.1473392223633127 + -0.2314405061445512 + 0.1459719401193021 + -0.1136173010133768 + 0.006868532856616406 + 0.02400895591422874 + -0.00140889397098312 + 0.07962126481284934 + 0.2570673940922909 + 0.2279872117501605 + 0.01066635433307934 + -0.2524576715800825 + 0.04402546277869483 + -0.1891818569796238 + 0.02491066047065214 + -0.06917415231101073 + 0.05843516739505776 + -0.110344662084734 + -0.004722266458798184 + 0.1407029769762403 + -0.0681792501302895 + 0.0728679211868621 + -0.09338393260688856 + 0.08571355216912344 + -0.2519953195513743 + 0.04142534451424247 + 0.1759653276726652 + -0.1958231103718363 + 0.03723831697901804 + 0.2646310160443111 + 0.1403640832729521 + -0.1018280651378107 + -0.1731322699109423 + -0.05120455192347869 + -0.001620598747993561 + -0.216583888020244 + -0.05044656277776705 + 0.03362227898942541 + 0.256463105846393 + 0.1215738701026295 + -0.005237128515646541 + -0.01022664676506063 + 0.1004277789860339 + 0.07712816122879944 + 0.1078374290208138 + -0.007194865777990773 + 0.1876551699642019 + 0.001667350295852293 + 0.02867937541054041 + 0.04517293409604164 + 0.0937114515641464 + 0.04633236924123863 + -0.1006494697492672 + 0.0003997197461487522 + -0.1220211830864603 + -0.1356895851520392 + -0.08619539425047287 + -0.005520532485616399 + -0.1622350543024395 + 0.1329943913962352 + -0.05133839832939446 + 0.06049281304004884 + -0.1380009534292445 + -0.0307093703266272 + -0.08189895899890301 + -0.09582785752375117 + -0.0133575494018252 + 0.03102839653371089 + 0.1113109805250389 + 0.02820468239319545 + -0.0905428916681274 + -0.05018668575904902 + -0.04851622012133064 + -0.1322551094153764 + 0.03595758536261508 + 0.05241541823993601 + 0.09172724805967761 + -0.06604359102903488 + -0.07165658896802339 + 0.1102900466151579 + -0.04752197349369227 + -0.08734046422401183 + 0.05591510956639406 + 0.006237028274019086 + 0.0857669005057204 + 0.05031680710561896 + -0.1452009830004442 + -0.05728141241003363 + -0.1012379336542239 + -0.1854106056175622 + 0.04013411401239173 + -0.04897801504707037 + -0.0637802936013028 + 0.03357712506802858 + 0.09828752550925135 + -0.07136897380156022 + 0.08090884282108722 + -0.09502012443304242 + -0.01161741856411765 + 0.1226464776813545 + 0.4485759372466924 + -0.05015434808813306 + -0.1744905663010217 + -0.2358783567264802 + 0.1040871860255075 + -0.218228186542194 + 0.05162613366267214 + -0.5825444454694714 + -0.01614290196515434 + 0.07456015276006371 + 0.1418633731961386 + 0.1795583698412907 + 0.03381238488305453 + 0.0641206581459849 + 0.001235302052984547 + -0.006611515360967271 + 0.1564581816138022 + 0.141106710505395 + -0.08431365731908896 + -0.009499002919999685 + 0.04644193436697899 + 0.2307887457874641 + 0.06050815293330995 + 0.1143476769885243 + 0.2110614716643876 + -0.2520013744550498 + -0.1146434935033729 + -0.2128355272346812 + 0.2014480460676106 + 0.09181113139079973 + -0.1056804973878586 + 0.08361396201986253 + 0.2518627168471895 + 0.1044295499804132 + -0.0406760446165754 + -0.07860006405826045 + 0.2528533561426618 + -0.1517541335513065 + -0.1025524098656186 + 0.05673539907367186 + 0.07782671150468863 + 0.001871582368684291 + -0.04449885254367604 + -0.03126683895503429 + -0.1051607436456349 + -0.2244141685950463 + -0.008170682034190205 + 0.03879446505442504 + -0.1628287294733831 + 0.05642526266835852 + -0.06253827842498424 + 0.331488732904181 + 0.001724232810947692 + -0.3905681921687634 + 0.05895642348297336 + -0.1119125616668234 + 0.1662986332997487 + 0.1434946617819624 + -0.07435548186449015 + -0.743880033080766 + -0.02644796415833742 + 0.04367084422748885 + -0.1834752372963459 + -0.02560951051033576 + -0.07631670614634718 + -0.03255868057230467 + -0.1167436877537004 + -0.02272147536737479 + 0.06411591472749349 + -0.01711449495783932 + -0.3044626495788554 + -0.1025855568381658 + -0.006429097263303756 + 0.1276193682095619 + -0.04285743679608941 + 0.1192362093919868 + -0.03412323380836676 + -0.08479576892930732 + 0.05299622364885363 + -0.07586777001477925 + 0.1309517244008993 + 0.05149356145811348 + 0.007873673151187054 + 0.04735582667900365 + -0.1654823590931954 + 0.08008416420393097 + -0.01715419516027902 + -0.007799091890092146 + -0.05088691456518094 + 0.2452605269787489 + 0.1546863842593431 + -0.2897062969332454 + 0.1188305054507049 + -0.07850503665204994 + -0.1006540439965697 + -0.2558986811122662 + 0.01548507621356168 + 0.07329585410572076 + -0.1370082978264821 + 0.1387774740885949 + 0.02955181581980287 + 0.1444144371420732 + 0.001837120217595092 + -0.1578832986296675 + 0.07882715158627783 + 0.1928696950352308 + 0.03224946199772585 + 0.01341000025888617 + -0.09598925318276851 + -0.08435593451679063 + 0.1228162643816339 + 0.008015286774561025 + 0.0228881821998962 + 0.1570899536013809 + 0.1095158523606059 + 0.01446583578714654 + -0.08895128018728235 + -0.001236351104625074 + -0.09216526425223315 + -0.06910048027843081 + 0.1502827463066932 + -0.02645425706844879 + -0.1538238485937606 + -0.09373051983743103 + 0.02993235896387325 + 0.05922767058409489 + 0.1931404783602182 + -0.2580179446158961 + 0.1319803253620105 + -0.0610923011835895 + 0.1136388376870395 + 0.04235085121945019 + 0.02087704833914409 + -0.1097924577012104 + 0.07209542544760648 + -0.08731372091508521 + -0.063858737454594 + -0.1110311004225679 + -0.03257993814386672 + -0.09986316072865788 + -0.05838994288214209 + 0.06026660892265399 + 0.06659362531488025 + -0.03691176136829286 + 0.1723615161788895 + 0.09643056698971313 + 0.06167212184878227 + 0.06048632545906647 + 0.106561067003565 + -0.2359146628019494 + -0.0856503881291492 + -0.099643415633156 + -0.1299553527488587 + -0.1610609809668669 + -0.04330429826958397 + 0.07109263745939573 + 0.09291327612335114 + -0.1843812962021002 + 0.1013587594778311 + -0.03519803794281224 + -0.1078463848683327 + 0.0909954873993804 + 0.02351873163478438 + 0.08716975720936852 + 0.09728441875793437 + 0.1864120685550244 + 0.09595823902078447 + -0.1451589532866548 + 0.01640819868298184 + -0.0561591030940127 + 0.1338230159271746 + -0.01851799790476288 + 0.07011706705491963 + -0.01918525560968478 + -0.08029296938813098 + 0.07278078422728794 + -0.1135486288809505 + 0.02457002483323539 + -0.0596770669792222 + 0.2358769742082185 + -0.2400165177972425 + 0.08009438860952148 + 0.2424825159792996 + -0.008410432856421089 + 0.02011138695890911 + 0.1780224878404248 + 0.1424454598257794 + -0.05871314571253786 + -0.09512264323598589 + 0.1371897600998222 + -0.09056466252358075 + -0.1854181803259646 + -0.2109512305338813 + 0.09803982108185796 + 0.03598251874938754 + -0.04517478104099741 + -0.04854246064512729 + -0.06171789472616177 + 0.07192616766614239 + -0.03708658598751851 + -0.01567456113454775 + 0.03187402259986397 + 0.05677710270208582 + 0.08741110014562621 + -0.2753834455814234 + 0.0402215068984251 + 0.001435929594174574 + -0.03611589497412362 + 0.007823493431096024 + -0.003238811581184531 + -0.2068030895775749 + -0.2594894484833802 + 0.2144522619103169 + -0.1280545220519629 + -0.134423044690689 + 0.0913785824982643 + -0.06794205571613246 + 0.01436313583963213 + -0.06666843135356472 + 0.00838343184753052 + 0.06888419434911967 + 0.2325929290607184 + 0.08681794826751776 + 0.1593828431302552 + -0.0971809489452081 + -0.005808009595889368 + -0.06696428436631012 + 0.03116172093868571 + 0.1198006010171893 + 0.1584776439167764 + -0.03353484654982301 + 0.0926434116160393 + 0.1045065496719981 + 0.06503528577764309 + -0.05100480215807208 + 0.2010842588680187 + -0.0726139584172765 + 0.1975982144772545 + 0.02064828836619831 + 0.1142919992778068 + -0.0463195959649861 + 0.03451511108502742 + -0.08986324087716212 + -0.1767873512546086 + -0.1247911188277607 + -0.1398351533981865 + -0.2721859928562543 + -0.094640776176979 + -0.05921379350247209 + 0.2545959570106689 + -0.1106979387583882 + -0.180340863682782 + 0.1531141947425265 + -0.01814999583861644 + 0.1670941187078815 + -0.1504044341610136 + 0.368068076988876 + -0.1145625107919577 + -0.1011895529635533 + -0.1876994034146107 + 0.2110545262545824 + -0.06033059066490179 + 0.04113581812067183 + 0.2507545279143593 + 0.1255650058849573 + 0.1443145310492009 + 0.1252464690064321 + 0.1293592914089819 + 0.09720477364753313 + 0.1440814100814087 + -0.1511182191743992 + -0.0464273303555949 + -0.03428424282005958 + 0.1791273628939941 + -0.08208633904799664 + 0.04671543365037168 + -0.01056477561293342 + 0.3280100816934571 + 0.06032636234666212 + -0.01359310216640612 + 0.1919570464308755 + -0.0873620119777706 + -0.02203560019350116 + -0.09774582328771275 + 0.1148398538982248 + 0.07421430013508032 + 0.003495306017029558 + -0.2222163726228187 + 0.08997589458793422 + 0.1696783366534761 + -0.1255260657153987 + -0.007072320209895626 + 0.1276347303962281 + 0.1292982787448447 + -0.05208297537677408 + 0.1479841311882314 + 0.04822554642615769 + -0.131141197759718 + 0.03471180741801515 + -0.06440961118901059 + -0.08722003818511585 + -0.1441997814585887 + -0.2274125474961627 + -0.097169489440387 + 0.02773088947569199 + -0.1070466485408921 + 0.06902503587091795 + 0.1311954112343072 + -0.141284481173385 + -0.04546677580696161 + 0.1097978230835506 + -0.08057433169438499 + 0.06757099048783766 + 0.07174731709769074 + -0.02851849012567256 + -0.3757146075638175 + 0.2328719117865827 + -0.01005557396472817 + -0.1243003275634562 + -0.04595478016296822 + -0.044100267647423 + -0.138084140211752 + -0.15511164224655 + -0.2178613785661863 + -0.01691927442642227 + 0.07818793707265874 + -0.1341944968282519 + -0.05851098802706113 + 0.1045252256364899 + -0.0499496819284715 + -0.1902526701601442 + 0.07196166882139192 + 0.004072779842996579 + 0.0160270595289024 + 0.04695225902353219 + -0.04911191224655075 + 0.191892831327582 + -0.1444945058834267 + -0.2202853904366343 + 0.01006205721444285 + -0.09504504271660796 + 0.1401082316439268 + -0.05821947588738329 + 0.01428714349737697 + -0.04498780531374046 + 0.1007395382555364 + 0.09608177306795511 + -0.1427377335384288 + 0.03727287969905327 + -0.1777903785780568 + -0.09485022788467795 + -0.06500052025496814 + 0.09284764092538193 + 0.1299617494659396 + -0.03042087319097689 + 0.1796893932241038 + -0.01073288538730337 + -0.1049688058609258 + 0.02829700538848619 + -0.285330643098704 + 0.1050696416419029 + 0.1765518138946547 + 0.08420673001179661 + 0.06970816483959348 + -0.1530962034710843 + 0.01236764325505881 + 0.07420243094544632 + 0.08905349755618586 + -0.1293428263821592 + -0.0263365993699912 + 0.0004047189157212132 + 0.07588363274246439 + -0.008464820354582242 + 0.02020185026750284 + 0.1244787239784793 + 0.0159723831505977 + -0.1982292587525092 + -0.06697682688310315 + -0.03613463148953804 + -0.1652780548885115 + 0.01438819929671103 + 0.0436618379304702 + 0.02491627491504792 + 0.008404475967987952 + 0.1148907444943133 + 0.0311937852377651 + 0.1303962606770908 + 0.002384966791908356 + 0.02716251179498693 + 0.09946937530571996 + 0.1321520060976324 + -0.05438432657939025 + -0.08340889495867501 + 0.1640467519825544 + -0.09103333261515581 + -0.1638472616753343 + -0.2122019615013457 + 0.103203938253611 + 0.2671611132079018 + -0.01586821097307979 + -0.07537445417268018 + -0.1206608893246473 + 0.2694225111514082 + -0.2159889392117946 + 0.1132074492364467 + -0.1044352839100796 + -0.1527095029381632 + -0.0009496288578566223 + -0.06634437061701783 + -0.1224661849351588 + -0.02970341668303083 + -0.006863288596291386 + 0.1175260476012279 + 0.1070414474675595 + 0.03480914513317275 + 0.2048299438497757 + -0.405880839130927 + 0.06268356595061511 + 0.01874398055316319 + 0.04569425390720752 + 0.09017430723950665 + -0.02460268063576581 + 0.05359884760024468 + 0.1460005901313657 + 0.05197464448943807 + -0.03592257968612141 + 0.31299478823909 + -0.07515948363432123 + 0.121321084016924 + 0.01263599841656247 + -0.14858359150611 + 0.1195877374674842 + -0.198524701721824 + 0.1120248835720462 + -0.04162710216587762 + -0.05290302292867322 + -0.02598187473458077 + 0.07997285485503414 + 0.03011143126414827 + -0.06664724864047192 + 0.04072436580352223 + 0.2088715140920505 + 0.04210225486461003 + 0.07918849123899123 + -0.01107329084409914 + 0.131163883735306 + -0.1444678082212088 + -0.06088597297014842 + -0.0919600166476546 + 0.005007240825029527 + -0.2956838950306138 + -0.05916747318376518 + 0.03896048279150401 + -0.02436983603028851 + 0.001561980004824293 + -0.06762785302309214 + -0.07194296837988168 + -0.05202154642029872 + 0.04532706723082909 + 0.0473193172319981 + -0.3924823907934017 + 0.02590495826419959 + 0.05103234693170136 + -0.06220339572621125 + -0.1128683942228634 + 0.003621463285539008 + -0.125072068400005 + -0.2535233192296045 + 0.2237082094153318 + -0.1238662605915766 + 0.2542353893090576 + -0.1260957503641726 + -0.04981271181918571 + 0.04375474922843847 + 0.01519398152190367 + 0.0924876875703777 + 0.04965081377876439 + 0.3962923002924593 + -0.03785891536828403 + 0.09987244387398275 + -0.2329998276014797 + 0.06861596344868606 + -0.1040800953732826 + -0.003137478320763371 + 0.1707473857482956 + 0.1509218157310757 + -0.06206676290586881 + -0.05765075673333001 + 0.1572077571817325 + 0.01517142860401577 + 0.01466221116289312 + 0.3175028771696407 + -0.020441517847501 + 0.2053511851279294 + -0.09067396104122771 + 0.1236767207071872 + -0.1986350982481705 + 0.06298112666774777 + 0.09385591886792403 + -0.1223713511164094 + -0.1147382813740545 + -0.006883009107352202 + -0.2168789477452491 + 0.0524124558261823 + 0.122901070985294 + 0.3646057870511434 + -0.06174545711317331 + -0.2560780266664009 + 0.09921395672527523 + -0.04178700799421948 + 0.1014635597977281 + -0.1169927589196547 + 0.3439174515523335 + 0.01199432919263614 + 0.1304317568047994 + 0.07617103031021842 + 0.1044847840807115 + -0.03219950718320975 + 0.0233797466830066 + -0.5104169205393798 + 0.1534422146750405 + 0.05325027156780688 + 0.07233797786357865 + 0.03979979991638729 + -0.0605452521243781 + 0.2943625825384965 + -0.02289376076416253 + -0.1454518292546651 + -0.005984339002386861 + 0.2320380109932727 + 0.01385619917191731 + -0.05491483316000891 + 0.05316412751874714 + 0.1291916865339855 + -0.07783323568050116 + 0.01374474890451888 + 0.08150744205473696 + 0.03674178822386485 + 0.1262867643310211 + 0.08388804589784947 + 0.07542899814341333 + 0.05635966174022341 + 0.1209635540242566 + -0.2382066524199452 + 0.01826229900511447 + 0.1312058722121623 + 0.05683785886574295 + 0.03431733966086457 + -0.1660524153169268 + 0.2202586177883086 + 0.1049052258434569 + 0.1142853214472117 + -0.1032444775412538 + -0.0968140206878982 + 0.1508012553582358 + 0.002264266730459902 + -0.007063442686006598 + 0.0090916702830316 + -0.1163386870841841 + -0.07373009327495732 + 0.03975460612836063 + 0.009278149561383859 + 0.1248891694484603 + -0.006270014750222492 + -0.1475526597316988 + 0.09901729400060909 + 0.1341875483226759 + -0.1259743022982773 + 0.05049364963162846 + 0.03708603329314558 + 0.02189707412706336 + 0.2416443444012894 + 0.2759794105981593 + -0.02951365353365954 + -0.05623552805001195 + 0.1714076105551529 + -0.03377215056195945 + -0.179444129915509 + 0.006621483580500045 + -0.1737789320240277 + 0.05809024247178902 + 0.03678901531717126 + 0.2776064805277152 + -0.09322912720286203 + 0.01334347063384463 + -0.1053048191767229 + -0.1604358264324766 + -0.03182783823646951 + 0.2033195668781748 + 0.1951645181678192 + 0.03528997505236636 + 0.1158156322771727 + 0.1134184255768755 + -0.1202015647878645 + -0.1186797026720517 + 0.1227052012633174 + -0.1855643716978661 + 0.06526929159457916 + -0.03972420017418311 + 0.07309256877660195 + -0.02977125684102818 + -0.1960654571418668 + 0.05010541748169863 + -0.02077266288446909 + 0.06825575668544 + -0.1751993227568611 + -0.01174347455288575 + 0.1016835056137998 + -0.1499648279313467 + 0.07675604994186601 + 0.1001469772779631 + 0.01564105129620838 + -0.08274643898747935 + -0.08984432890622834 + -0.3080101233397119 + -0.2155884556106073 + 0.1027420961564515 + -0.0110173254277038 + 0.03635824356612569 + -0.1322111365643562 + -0.1998777470782329 + -0.06383138275761953 + -0.07453898800212505 + 0.1504701447139906 + -0.02809264172900187 + -0.126485832782059 + -0.1156208284452664 + -0.03486958474586161 + 0.004898922209548031 + 0.05571979584879586 + 0.03497499654142802 + -0.04493023236790567 + -0.1265547423786091 + 0.1024300437717925 + 0.01267618383161958 + -0.1192666895571647 + -0.06480075713995874 + -0.001726164340527923 + -0.1743831685117497 + 0.01053318863133042 + 0.04032888011964177 + 0.1266044601787064 + 0.06838639787049788 + -0.08669433632776707 + -0.07699315754319193 + 0.05121379958454336 + 0.177834146977162 + 0.1193533926516111 + -0.1111876785928262 + 0.07363127328126198 + -0.001135007801882461 + -0.2334147050506218 + -0.2859990369490872 + -0.04662617214043142 + 0.04719597246866998 + -0.06423162712809483 + 0.1023702529027177 + -0.05550149057601189 + 0.2693097317610041 + -0.2542442786389534 + 0.05427865635843668 + -0.02289077387644598 + -0.06025298323649893 + -0.1004826230504436 + 0.06629417709563243 + -0.03709967089572237 + -0.0169610744075567 + -0.002088483266166478 + 0.1617962286550673 + 0.2761238829078564 + -0.07327915726179524 + 0.1477834362060406 + -0.5167831382879509 + -0.050516045200913 + -0.01625669977431896 + -0.0659940405649726 + 0.1069896895166956 + -0.167874241219339 + -0.07923803197233062 + 0.1513999395028791 + -0.02893003262506223 + -0.02118220407176248 + 0.01372312043503925 + -0.1155447497524999 + 0.1803012487250286 + 0.0009191828994382826 + -0.07906659895908262 + 0.1529982630253779 + -0.2459700679275017 + 0.1745745175499034 + -0.03473127916378869 + -0.2494665077804605 + 0.0942063728583513 + -0.0212656179108913 + -0.08824629408065333 + -0.1727791494378021 + -0.06116186083051743 + 0.1092743183721836 + -0.2118908450576671 + 0.1091442326921763 + 0.01762757150041668 + 0.001492888773122969 + -0.04467862159484848 + 0.1945377072484118 + 0.04372383237405544 + -0.01633997278586273 + -0.5664696917374411 + 0.0900023222205014 + 0.1024327770795413 + 0.03174159051346814 + 0.08168036960112228 + -0.1044473530416468 + -0.03258097577883422 + 0.02656364864392141 + 0.03960718729651969 + -0.06902131912284072 + -0.1923338759869059 + 0.05724682232359244 + 0.1291613069190952 + 0.1402420313973408 + -0.1743034410713866 + -0.01142430155843352 + 0.05379025830105558 + -0.23426665939346 + 0.1518271841478148 + 0.08647099126854747 + 0.2644879890017845 + -0.1792884256069534 + 0.06120768740122252 + 0.03363621005698549 + 0.06779670853307425 + 0.1399725066900526 + 0.07300773670183608 + 0.1497455715168628 + -0.04494168517881443 + -0.1487789330622697 + -0.123329993681653 + 0.09304462616250117 + -0.06260615465801572 + -0.002204251665977467 + 0.2241764656684518 + -0.01380960288266653 + -0.07683569365374116 + -0.1830754405431468 + 0.106624628845378 + -0.2126703228672125 + -0.05020566970742592 + -0.1064108580225708 + -0.1635788154299146 + 0.04654217148564559 + -0.08711541560158394 + 0.06487354608901222 + -0.3541464113397586 + 0.08098879721239594 + 0.2741172343682602 + 0.2319837004703313 + 0.01334847173582528 + 0.3426867530573805 + 0.03286313012828165 + 0.1354787168702271 + 0.1840121160671404 + 0.2179747841712582 + 0.0334435043309843 + 0.04328905383699076 + -0.3506744502335525 + 0.1489702975138629 + 0.1792090461456065 + 0.06675010992872712 + 0.3315298440973751 + 0.07944857640654217 + 0.08142924988923757 + 0.1039971573427152 + 0.02675596677429646 + 0.0932807011511798 + 0.001721874120625488 + 0.2433885293844283 + 0.1179481264819988 + -0.01824308026406813 + 0.04932863627365439 + -0.01607871508351662 + -0.4097972803841568 + 0.1509001197272528 + 0.09915526557508715 + -0.1411358964162583 + 0.00174289224332619 + 0.1476208008607287 + -0.149080629262399 + -0.01223541789522891 + 0.04344856097747963 + -0.06739497831074694 + -0.2958751909125948 + 0.04468156708035222 + 0.01699193206050237 + 0.04294568184329499 + 0.09625891514180991 + -0.003331663309702944 + 0.0394891310617719 + 0.01484353007705631 + 0.1893838285010545 + -0.06588620690023483 + 0.1192407653988873 + -0.03377543229773004 + 0.08055604468975913 + -0.03876485921154274 + -0.1998876806315399 + 0.08351025978705078 + 0.109838030443253 + -0.08342925523216127 + -0.1644979985086071 + 0.03631522039718456 + 0.1652052123374243 + 0.06517262376922202 + 0.02401161081769404 + 0.2358921310858615 + 0.2409577987266139 + -0.0008723446223863749 + -0.1051821186320413 + 0.07279272083909501 + -0.01892806487892615 + -0.005655646006455291 + -0.09895204107660432 + 0.03993877776603263 + 0.02003688466597598 + -0.1455666492089054 + 0.1508200186086192 + 0.1066092633752345 + 0.1408413121989664 + 0.3237896257480205 + -0.01988463626128929 + 0.007512606264929994 + -0.001569961135358605 + 0.2901569209547472 + -0.08937826325723433 + 0.07575379524431722 + 0.05750677176640619 + -0.08419182154470206 + 0.1415199704162118 + -0.007489094542185645 + 0.2833125760955886 + -0.06330825782732212 + -0.08038437758557827 + 0.00335894671541253 + -0.1651660867404519 + 0.005274797456770841 + 0.1451928119028927 + 0.0112763569329058 + 0.04349476330791319 + 0.1755574189852512 + -0.1004799935416272 + -0.08857135678157048 + 0.1016336458639318 + 0.128089002707815 + -0.2033716433497825 + -0.06308347564939616 + -0.0374340770790013 + 0.1611866786641338 + 0.06284520137338571 + -0.1733160160414784 + -0.01277000452815422 + 0.05042123213034332 + -0.07605669574193785 + 0.1541596046567756 + 0.100129475465233 + 0.1502604053306998 + -0.1815341230182427 + 0.05781232623561872 + -0.1404702374844343 + 0.004316962777268882 + -0.1229997303048702 + -0.1008330870514547 + -0.3862619069515442 + 0.208386591312998 + 0.00705287407151345 + -0.1145430834370256 + 0.03117859179772877 + -0.1790100627788533 + -0.317114755779024 + -0.1465073188758438 + -0.05678938881741846 + -0.04631415161620381 + -0.2602796885870445 + -0.1609362113998376 + -0.1564632165577046 + -0.1888152536312644 + -0.03969244829851229 + 0.02612137771711488 + -0.09543246562696969 + -0.2183968199062007 + 0.05932022007254949 + 0.1119422932084073 + -0.05863555273270557 + -0.07311929300317055 + -0.185054570373021 + -0.08111145820914961 + -0.08229595889898869 + -0.08336248446315815 + -0.03355480185186703 + -0.0137739865574326 + 0.01578423759247887 + -0.134280858407766 + -0.05979114807592321 + -0.1359082924315047 + 0.2251368739066763 + 0.1284719551357331 + -0.008720901210605873 + -0.02170581118342002 + 0.03098058198636323 + -0.1516797189958598 + -0.1182644098776825 + -0.1585499139498735 + -0.4004687252549597 + -0.1083307051514876 + -0.02477912039670704 + -0.06401091446007764 + -0.00465289972803625 + -0.04593001902571633 + -0.1553585199910524 + -0.03401223036656075 + 0.02175754426725177 + 0.04032536711263271 + 0.02332800491697365 + -0.07758927803027214 + 0.01505334199605501 + 0.1159277332788187 + 0.2246696640606345 + 0.1821811913622563 + 0.03372106411337247 + 0.003076116559792473 + -0.2321034140537513 + -0.2014303771732046 + -0.005825533774552373 + 0.0003041051573775923 + 0.04380826758018026 + -0.06261541589566881 + 0.09123212191409814 + 0.03155889220687966 + -0.1051582789554929 + -0.019320322679914 + -0.4296919773018761 + -0.1267327090081997 + 0.2460451494795493 + -0.09815740987293466 + -0.112065326760333 + 0.04441953514823409 + -0.1038860449114877 + 0.0006600456433968109 + 0.06011012798096176 + -0.07961303018752405 + 0.06889443179937985 + -0.1722576091260162 + 0.1272105046165272 + -0.246875791317345 + -0.1391520490300331 + 0.1368616549424919 + -0.2561672078639782 + 0.101408160595333 + 0.0632683649049635 + 0.00183405543497394 + 0.01030663525930626 + 0.07710038204783168 + 0.04191756022354327 + -0.1945866467252047 + -0.1956579413332658 + 0.1495908114577365 + 0.02566416481134048 + 0.03281862995472427 + 0.1750041255896567 + -0.03072004489063606 + -0.1180937560974679 + 0.05465825796076283 + -0.1293249330045187 + -0.05106361463711692 + -0.2154063873615947 + -0.00929286894729823 + 0.26662799813664 + 0.2404808370652683 + -0.1074050002949689 + -0.0251094620755515 + 0.06267698473230983 + -0.04101375796257579 + 0.06834772494667074 + 0.08446323900121717 + 0.0007030897104779825 + -0.01788360140019017 + 0.1075996994286616 + 0.03829468072288923 + 0.06483195079665234 + 0.1428459774551653 + 0.03807425408719391 + 0.00172009335770463 + 0.0852300086246448 + -0.1436778649299378 + 0.1547867246446074 + 0.1686405197787893 + 0.02386955669903841 + -0.06969960445004166 + 0.2056324130053931 + 0.04415675901676435 + -0.02879603819070192 + -0.2174676885227549 + 0.02320494759177774 + -0.2064085939414105 + -0.1115869662551407 + -0.369623368937269 + -0.2438690336665204 + 0.01208375588372786 + -0.05335290497420438 + -0.08374412732522361 + -0.002591990189751939 + 0.06159414959258906 + 0.1348096777210641 + 0.2282425738739924 + 0.1991950462659057 + 0.1721361435316378 + 0.03823591687534759 + 0.04599802966822675 + 0.1691568621964841 + -0.08684860820319985 + 0.002458687877128006 + 0.1567772711376126 + -0.6061634130980867 + 0.08482804187365316 + 0.09301007245418171 + 0.02322821426035823 + 0.08833443865908727 + 0.1660776461897365 + 0.02882327432218191 + -0.01120870775886737 + 0.108747179892392 + 0.1909085004504499 + 0.006521111454003459 + -0.5798279730779259 + 0.08115144774162875 + 0.06379528850046974 + 0.06597844236811323 + -0.1150131081562423 + -0.2595789720827441 + -0.03921162143577954 + -0.1889725044114855 + -0.04946176534139222 + -0.1332932698562622 + -0.005483179351226585 + -0.09406593199267928 + 0.07027042011176331 + 0.04140933885974341 + -0.1220306059795954 + -0.1784630885326045 + -0.06183513688957735 + -0.04620779652230963 + 0.01208544382877731 + -0.07593065279451829 + 0.005310123626712982 + -0.0537404178712245 + 0.06509767254169235 + 0.3095656335403331 + 0.06644844505785756 + 0.1046541918591089 + -0.2943514782239701 + -0.07184880984078473 + -0.150286594575941 + -0.05118008547225355 + -0.02902023774849643 + -0.01404467375295322 + -0.2373670524378622 + -0.07702324621789179 + -0.04895588030861381 + 0.06930851900854594 + 0.06091788362428961 + -0.0487272679060729 + 0.1999840920560406 + 0.2847516221314755 + -0.006490807811043483 + -0.1177768050221116 + -0.003928377152762068 + -0.06807953367482994 + 0.00815797407149558 + -0.05876264057938538 + -0.002709513095030907 + -0.01544309942595336 + -0.1921996488157096 + 0.1845996938092963 + 0.08706799328370383 + 0.08714351889716213 + 0.1229346248358035 + -0.3809247883884744 + -0.02418657300916352 + 0.0269583373305321 + 0.1983369226201439 + -0.2709090627460813 + 0.1377633632128844 + -0.07477915185102726 + -0.1271397141138801 + -0.04480297917247535 + 0.003651388956419065 + -0.07738439626008101 + 0.02361201279791315 + 0.09225393181949118 + 0.05340439521830287 + -0.06664910747875021 + 0.07683235450873378 + 0.008829235914813105 + -0.1132187632823483 + 0.03651116945295849 + 0.0251097318352578 + -0.08889740286853948 + -0.1154001052002589 + 0.1594637821987131 + 0.03843906757654038 + 0.1126844002169019 + -0.02670792851573295 + -0.002936827904473006 + 0.1040632719247211 + 0.1279576088824421 + -0.08187550891668971 + 0.01448635428902653 + 0.07365691967003778 + -0.128381333959134 + 0.2507229622342359 + 0.1428853588807213 + 0.2112289983206825 + 0.1112981412679344 + 0.1236019560656137 + -0.1095517469213071 + -0.05610350103106206 + -0.1287765694240627 + -0.2204735393882981 + -0.1947620806931097 + 0.2661820493338552 + -0.05727346964422059 + -0.08777698515797741 + 0.146862217082062 + -0.1211727226851576 + -0.2596105058855678 + 0.03298028440934461 + 0.01695093509570031 + -0.1353865471488698 + -0.2853070334978341 + -0.1076480925415555 + -0.01868969867909531 + -0.2755694635705666 + 0.08654685680010697 + -0.06774074042738799 + -0.04503361833983752 + -0.2858509436932885 + -0.006312798140391423 + -0.1010457793245181 + -0.02194637148278473 + -0.1209844657919036 + -0.09542887781864266 + -0.1665141985613761 + -0.02747941032078098 + 0.06506225651289597 + 0.03138345843500882 + -0.08489390382410648 + -0.001164325447961441 + 0.003842815998187988 + 0.188216079875226 + -0.1172106582364393 + 0.1588972143009124 + 0.1376983275026621 + 0.03625728163813317 + -0.01756119064575194 + -0.07975850805512234 + -0.2525580915069717 + 0.1225771086631814 + -0.001084702257775424 + -0.1828422228590859 + -0.1557494369505046 + 0.07795329534776511 + 0.09472711027862084 + -0.001833963694330049 + -0.00898099402117189 + -0.09376805496078298 + -0.1661632022037644 + 0.1609761058075417 + 0.06938295032553456 + 0.01499141464340691 + -0.09033638416729012 + 0.002273262915752048 + 0.2752084675754887 + 0.03188948749777691 + -0.07466951045328889 + 0.058957066698073 + 0.007381213020779487 + 0.1336484465438573 + -0.1805294252205066 + 0.01016316826432791 + 0.02464567100390933 + 0.02375319672877546 + 0.09395357258690983 + 0.1367843113114702 + -0.09273687404562907 + -0.1147744683144654 + 0.004700225990019173 + -0.2844801236877633 + 0.02943023908257679 + -0.01598638200216662 + -0.141300900576971 + 0.04039618734261058 + -0.1639282340787453 + 0.0765906998646597 + -0.1713311368050122 + -0.01092396053232519 + 0.0114560370981295 + -0.004751009039853939 + -0.2087227424059737 + 0.184480184554378 + 0.001043298209004864 + -0.1037353952645325 + 0.05051265538013455 + -0.1312447302270093 + 0.1809881017891309 + 0.1294350311522487 + 0.07842999109776783 + -0.0164205485729848 + 0.0002513185691293265 + 0.06300828324358586 + -0.21952091989477 + 0.1282120730099955 + 0.09332454855351834 + -0.07347927914594297 + -0.05256809557858914 + 0.02692370545350153 + 0.01463401338307507 + -0.2200433742206598 + -0.1067900811897174 + -0.1218573152310595 + 0.1025261155401048 + -0.4035504024103722 + -0.1237795037065591 + 0.1484483461691831 + 0.2547497308795001 + 0.02793250367947491 + -0.03492943338759393 + -0.1034132879006144 + 0.05232615436444929 + -0.1010810155523437 + 0.03216142504305022 + -0.2088791441861932 + 0.1040330702029325 + 0.05014918700639624 + 0.07862518163601354 + 0.05927749034429172 + 0.02956841065647962 + -0.2012967975789961 + 0.003938353509400875 + 0.09159030727319518 + 0.09432302097877748 + 0.08680770183530477 + -0.04252292014899794 + 0.03696641305128692 + -0.1166550618014055 + 0.01748073416192691 + 0.04089595204065451 + 0.01137504179012836 + -0.05903219959174481 + -0.01818124940614758 + 0.04812882453035804 + 0.2362286934568873 + 0.02034513117836981 + -0.02285896151518186 + 0.005471949281347859 + -0.06798392521056063 + -0.1047102982122652 + 0.3688688592810885 + 0.03035280270697957 + -0.03417058483170611 + 0.0193786406183001 + 0.1661469777636171 + -0.07065347570250144 + 0.007467038833007271 + -0.1502546342421678 + 0.083877329161976 + -0.1661607003447915 + -0.1074311013553391 + 0.1661982342949016 + 0.1979321484652738 + -0.02043711751769698 + 0.03682639398821854 + 0.03644007402503712 + -0.1111992055960391 + 0.2790245162208053 + 0.005369490324460527 + -0.0314882128296991 + -0.01417981232737644 + 0.04828101676321944 + 0.008977275006716955 + 0.2043868592912931 + 0.04365301879191937 + 0.1305156044209719 + -0.01794485993614705 + -0.2384070578414621 + 0.05744150678398646 + -0.09762703357797536 + -0.2678785778945201 + 0.0346727597244921 + -0.2780084831563379 + -0.1499419512722171 + 0.1038933245569644 + 0.03440607454388061 + 0.000274370782536458 + 0.06111310170522111 + 0.08608971642796071 + 0.04987573262615801 + -0.04626504059303834 + 0.1698993704052897 + -0.06281041299806465 + 0.04528977818330598 + -0.123392654940005 + -0.0290676987885179 + 0.107881616484137 + -0.04178073164162893 + -0.03764153500148977 + -0.2824760561583472 + -0.001557878213629696 + -0.1640962383796669 + 0.06850449820069332 + 0.01804390116308751 + -0.105628013732652 + -0.1505808251628635 + -0.08082331342730152 + -0.2008307943952176 + -0.02991474972227747 + -0.04271818230162084 + -0.120879166950042 + 0.065444494307024 + 0.1856453759031841 + 0.04812894538925469 + 0.04440193799295528 + -0.007132304738937823 + 0.02234193396576895 + -0.09070804057526791 + 0.0249839423657245 + -0.01598184712240994 + -0.002039125476166264 + -0.2826860340094195 + 0.1237698069602635 + 0.005176355423163174 + -0.0676378204351348 + -0.102549818025726 + 0.07228683717461937 + -0.03231537860473729 + -0.06025380539328302 + -0.1067148913657218 + -0.1832348624262625 + -0.1186896551549737 + 0.06534932782785902 + -0.04148260038373607 + -0.3297449271049483 + 0.1638800049942212 + -0.1047269438797595 + 0.06573542409555815 + 0.1721605583437557 + -0.1604184367461875 + 0.03905030110637008 + 0.01086051951898515 + -0.01894004518831463 + 0.06860012102710784 + 0.02071178364009996 + -0.07564673142046621 + 0.01194018131385199 + -0.01809349589871487 + 0.06818136240553006 + -0.04702563798760495 + 0.060462037871139 + 0.005590683401130687 + 0.01791891579467166 + 0.05911651275922077 + 0.05864473705533306 + -0.02266784974209638 + -0.06675284352905796 + -0.2306891995624698 + -0.008914613841774933 + 0.08925315177057583 + -0.02838669816570877 + 0.1244219598355526 + 0.1306714961625057 + 0.1190050559289682 + 0.136603365054152 + -0.3123502047995758 + -0.06066587616933178 + -0.04621714114092183 + -0.3003727436883856 + 0.06131468434924262 + 0.08072593320910279 + 0.02622731489628235 + 0.1359507126697057 + -0.1439553612936746 + 0.1419399686336321 + 0.01657293197267144 + 0.05013144712041896 + -0.1174187439667581 + -0.1229456383384699 + -0.07021784461102953 + 0.1760995872620846 + -0.1398593474134106 + 0.2287227549937715 + -0.08096577250908631 + -0.004426402139883642 + -0.06228587044321769 + -0.004607207370818548 + -0.2171647049713261 + -0.0637788403807322 + -0.1596330784798335 + 0.1641262828017135 + -0.09976515128050771 + -0.03789548774364188 + 0.06395283979531464 + 0.1600188622367744 + 0.03074946009474685 + -0.06847802141332188 + 0.03237742488766973 + 0.2120874115856863 + 0.2028964080744353 + 0.04566064630909031 + -0.06389285204871999 + 0.1158669133379179 + -0.07485438195467638 + -0.07265337877706275 + -0.1705058405414504 + 0.07519232883401432 + 0.1138051560296518 + -0.1563016357246378 + -0.04385789255021381 + -0.1160164439433906 + -0.03769613232459991 + 0.1767705713716731 + -0.0563029003721063 + 0.06358569294818638 + -0.07699336081058232 + 0.2111513303382762 + -0.1106989508568593 + 0.02360204026244463 + -0.03494908146075507 + -0.04116963449027391 + 0.2216215630311471 + 0.02908444897091008 + -0.07156157776660475 + -0.2366968827800979 + -0.03163552380653103 + 0.06905817727794072 + -0.002536916526160523 + -0.01466988290168243 + 0.06242703809006644 + -0.06243224614138568 + 0.05271893755065048 + 0.03307773593364672 + -0.001177328042041443 + -0.09278396139545916 + 0.05035883368350171 + 0.029819047035332 + 0.1094461945652439 + -0.3241135950284725 + 0.004440857096820299 + 0.04345434653676448 + -0.2578424316428754 + 0.1058005119317326 + 0.01730233901439584 + -0.01975958618579435 + -0.07025976285183216 + -0.1274311117652878 + -0.09362778358797785 + 0.09640837063806885 + 0.2136431668073824 + 0.0437555628860183 + 0.06372522484508009 + -0.1388022151894868 + 0.1502159361592025 + 0.1066471896792283 + 0.1211316597583722 + -0.006932933763685157 + 0.0433171775255522 + 0.0373504282424748 + -0.10731333442803 + 0.1505106288169171 + -0.05859110059571048 + -0.1658760038288777 + -0.1434988650066946 + -0.07485656307655052 + -0.05611263479659877 + -0.03785225140850908 + -0.2146191449945687 + -0.3329667488273335 + -0.01473046367218078 + -0.2292276084334722 + -0.04867558711499703 + -0.01335061491191113 + -0.09277123822653682 + 0.008395681804528488 + -0.03271414188514318 + -0.1724157876155324 + 0.07512239612503882 + -0.1679458986795618 + 0.05823397020787569 + -0.001364809187555237 + 0.05736041145111728 + -0.003497481747117358 + 0.06560215237059054 + 0.06151686689615499 + -0.05588884299574574 + -0.1634717399528579 + 0.03258400693485732 + -0.06196460148182169 + 0.04743126116872873 + 0.02444569123824265 + 0.2544798947193593 + -0.1394049754197734 + -0.1468492562759236 + 0.1637587461340966 + -0.004307009767128407 + 0.1401029151418366 + -0.0351456964596356 + -0.05604348444296517 + 0.1874162088503692 + 0.3927244262910226 + 0.0290206574198427 + 0.1080021675088202 + -0.1162972538889056 + -0.0699340844992085 + -0.1194181050711391 + 0.2290374918247552 + -0.02681164614921138 + 0.02383497831161389 + 0.06831927803638151 + -0.008059702069016163 + 0.06104288327438496 + -0.04632576978061029 + -0.2150038743409605 + 0.06406761077878008 + -0.03298930021665651 + -0.0984231714940946 + 0.01546269795518636 + -0.3237124964334551 + 0.1349091243788539 + 0.05457026197896756 + 0.05992829615859915 + -0.1010785172308407 + 0.1369516495270364 + -0.01252664320393353 + 0.07598679622006517 + -0.1786265303893693 + -0.1419243011344121 + 0.01485387875768312 + -0.6192285232430708 + -0.04985276818828194 + 0.001997299065577684 + -0.02759831723738511 + -0.3096640531402383 + 0.01003320099005055 + -0.02979157180962045 + -0.1177246713736268 + 0.00709662118902067 + -0.2168238201105701 + -0.3026117749231387 + 0.02963810853696305 + 0.05494398422103806 + 0.02529345646419047 + -0.07776866290509794 + 0.07175586594468458 + 0.1165086935565908 + 0.06424004949363959 + 0.1902396429477159 + 0.02635292144992934 + 0.1245306728893237 + 0.08408404293418334 + -0.08548187456389662 + -0.04378426766670829 + -0.0954651786569372 + -0.08472911189901509 + -0.08527754766534512 + 0.1090545784365619 + 0.1076798762789478 + 0.04082367620288804 + -0.02901521821842885 + -0.1330813856199282 + -0.1030171681011061 + -0.0406970532176619 + -0.2796852145803527 + 0.06635538073306607 + -0.0625645705847102 + -0.09147119235794353 + 0.07438596014907495 + 0.1210580719073444 + 0.104745870946697 + 0.1702391451066284 + -0.1320146753106412 + 0.0299064147546777 + -0.0595403734608253 + -0.01278921150453554 + 0.06103256952223652 + 0.1882550587124597 + -0.1343668802104494 + 0.0631129991253106 + -0.07934019711958883 + 0.01201513672380478 + 0.1172233867072231 + -0.04947633196342413 + -0.07870281870516233 + -0.1435487549226015 + -0.2575348905012878 + -0.03798459066131626 + -0.2727538736801811 + 0.2484974938214449 + -0.05795337692219548 + -0.1999913651242681 + 0.2522798310967101 + 0.02698128233420108 + 0.0833028924986451 + 0.06649185480315546 + -0.2411451832821562 + 0.01633080520325001 + -0.07609859242188781 + -0.04247559909162969 + 0.07738309127212294 + 0.00338504944113374 + 0.02759211327553412 + -0.062832083534875 + 0.04143828656425674 + 0.009073018473040258 + 0.1419465999688319 + 0.07128105459692202 + -0.01848987171334482 + -0.02259148678743529 + 0.02491359839243191 + 0.01783047751925651 + -0.01442395569032092 + -0.2027928721149563 + -0.1598159994989173 + 0.03842714305757287 + -0.008384169377587621 + -0.08880299076422628 + 0.02079037965729929 + -0.03671362409174479 + 0.06973205315710705 + 0.1063069775346068 + 0.1007176612891763 + -0.002547602650709032 + -0.02700922622045116 + -0.09703937804374069 + 0.05950753545508661 + 0.0507485771781551 + 0.07985287074546485 + 0.1817836436376768 + -0.1725753188714505 + 0.2018124545346996 + -0.02125262992036267 + -0.1389955022111425 + -0.004821234830264484 + -0.08821775432205033 + -0.04411838609251255 + 0.2264100411622824 + 0.09577882771570714 + 0.04386820998539865 + -0.03487017916397868 + -0.04453788418018581 + 0.1268747270609243 + 0.07437212842587976 + -0.1334871846804367 + -0.0724059218444012 + -0.05608205535374374 + 0.2326132060190554 + 0.02994092587015976 + -0.2089556167044889 + 0.0307205569385052 + 0.2100329072099038 + 0.1470463822501148 + -0.1108473213221753 + 0.0180421233819202 + 0.1926915008233758 + 0.2834135240492412 + 0.03981386172756802 + -0.1353756782207221 + -0.1316357648682679 + 0.1251917445532366 + -0.07122199797343048 + -0.06843443883418815 + -0.06471799506842645 + 0.04920451919097584 + -0.04966553488209532 + 0.09030407907133559 + -0.009032101019832373 + 0.3329343599524694 + 0.1077140326181361 + 0.2116763535918749 + 0.09572090976537226 + 0.09690546083088047 + 0.2116609787799568 + -0.04686920855405804 + 0.0218607548581237 + 0.02399391243619535 + -0.04534593475778261 + 0.08112859651845519 + 0.2334446290891323 + -0.008582300947611097 + -0.2305722476263238 + -0.0413794517229276 + -0.1110155935673876 + 0.04846596644900134 + 0.009376670702189865 + 0.06371692643620697 + -0.1262177887372313 + 0.002243370830352344 + 0.07522925987672718 + 0.02981543502381082 + -0.09688900661116427 + 0.1187022634635514 + 0.2121937407941616 + 0.1160820564728878 + -0.09145826358985815 + 0.1265546134597996 + 0.1239288672234961 + -0.218873561315173 + 0.06010108458356655 + 0.09184133777890542 + -0.0497281833890348 + -0.0764646030507192 + -0.05102912514365521 + 0.02849400911861337 + -0.05162216662868902 + 0.1932424320654136 + 0.1384606059076061 + -0.08799270097847003 + -0.1878590814284045 + 0.04201339478566018 + -0.0006645564187006181 + 0.01683382078521371 + 0.01262715095198261 + -0.008313080897634438 + 0.009995652060245303 + -0.1694766390039859 + -0.1915939699332303 + -0.08648825821462656 + -0.01825769682471006 + -0.1798777902610145 + -0.09917221514651982 + -0.1076235449927981 + 0.006472931840932583 + -0.1167483437189565 + 0.3296695003306915 + -0.06228780364996593 + -0.002629600483244642 + -0.05191930452281279 + -0.08694977269772103 + -0.2010664198842678 + -0.05648442893616653 + -0.04522512093437937 + -0.03900233986908162 + 0.1111104382835447 + -0.2126954149231985 + 0.1129761193154164 + 0.1494508746293761 + -0.007458460909668881 + -0.01605879162423225 + 0.04782514952142372 + 0.04590636480733407 + -0.1875383910479731 + -0.009154183090342357 + 0.1349569418108101 + -0.2276526472382224 + -0.1071252008719458 + 0.06749302105374287 + 0.1622229300062252 + -0.2781852298265187 + -0.07887328124863414 + 0.2694692883777759 + 0.03607529710022215 + 0.1481183486481567 + -0.06184326053558836 + -0.1730417754804224 + 0.01525077970179209 + 0.1561405994597077 + 0.02678032513693529 + -0.0008197120477443001 + -0.1530898484847645 + -0.001847636302208441 + -0.05110614815450206 + -0.008266118435312478 + -0.02473667511525696 + 0.05569216297511022 + 0.08004609750215154 + -0.1350936797929578 + -0.03104008993202642 + 0.05254690529371065 + -0.07021698690263957 + 0.1619352579102685 + -0.04774013275971477 + 0.08923569540698978 + -0.1007475489639843 + 0.135776142630528 + 0.1150462916600388 + 0.0322451299040322 + -0.01112626971319132 + -0.1604373055729276 + 0.08640957224394968 + 0.007749845426388811 + 0.07092711464746372 + -0.2288341889598747 + -0.1111153620865373 + 0.01284950736467663 + 0.1917962362109962 + -0.121350989274593 + -0.1619193800434921 + 0.009766252230125208 + -0.2185447500102821 + 0.06787029563053804 + 0.05123133944641886 + 0.1560039184081432 + -0.008265993533776123 + 0.05753488765027924 + -0.08931515682119745 + 0.1305485552418335 + 0.08516739237231388 + 0.04417580277271685 + -0.2388817817062562 + 0.01106863756299767 + 0.05034403890828894 + 0.06090714841574685 + 0.07730723735143495 + 0.1005535179537418 + 0.04161994673567664 + 0.1245826338715556 + 0.02590296946129248 + -0.008911236072077382 + -0.1571295891427713 + -0.06433320918472896 + 0.06306623391009464 + 0.02540275442119966 + 0.3067717439195782 + -0.1233173904652815 + -0.2499425266245129 + -0.1910383963171172 + -0.06385514171998863 + 0.03927738558934807 + -0.2231381271681863 + 0.07228567902119459 + 0.04786253900927035 + -0.06429441538918575 + 0.1595981778299712 + 0.08173468092895905 + 0.09811294770320431 + 0.2426138303451038 + -0.05896816906302247 + 0.08631485452582394 + 0.1190720926354649 + 0.02216332510794881 + 0.08027285957578843 + 0.2699765960020123 + 0.1330179192577183 + -0.0129612182607308 + -0.06144857440814451 + 0.1766057604623763 + 0.3637656530206659 + -0.1979580496373715 + -0.1272743278008463 + -0.07403992269645622 + -0.1190820717998966 + -0.05256178829659498 + -0.01743017925042123 + 0.1652132477967278 + -0.08397210979863105 + 0.08678607625537327 + 0.2690269233578607 + 0.004725727569335508 + 0.03657725758925761 + 0.03782683317786107 + -0.01527115734314086 + -0.03748412659968398 + -0.05184529043462635 + -0.08125696378463768 + -0.2044036502827531 + -0.02259796832914181 + 0.2306125846856311 + -0.05166341912758832 + 0.1007686765701985 + 0.02807602496517032 + 0.195397975895692 + 0.2477849475429904 + -0.1578389390132202 + -0.06778967285660908 + -0.06310468894237677 + 0.001152317090581645 + -0.02847159285392959 + -0.1644965691415145 + -0.004422672654226657 + -0.04582338763658627 + -0.03368514007381852 + 0.1036676916041419 + 0.01633088436745846 + -0.11428974481109 + 0.06236689654186239 + 0.01749034359008914 + 0.02853137340479905 + -0.007962212607277726 + -0.07785215475867532 + 0.0838684611198631 + 0.1974969030295401 + 0.1069244217460556 + 0.02422108189175057 + 0.0980456720803683 + -0.03801602309734344 + -0.06111899634518623 + 0.02441623516867221 + -0.2054311974185093 + -0.08081305627872575 + -0.1198518817220182 + 0.04034362071064586 + 0.05207350174491301 + 0.1974377976085911 + -0.06059255574100417 + 0.04792259565886958 + 0.05189266619617966 + 0.06818538193969763 + 0.04047283318606913 + -0.1017936717913432 + -0.04701905901973118 + 0.1229816793201596 + 0.1488015984903939 + 0.09661098734906357 + -0.1003106650446885 + -0.01537647740384916 + 0.1618204180858531 + 0.1571893218096157 + 0.01468400068843958 + -0.04071898294540913 + 0.1132891253111955 + 0.07248743091201217 + 0.01764528037644025 + -0.0004762474921353839 + -0.01498907130076845 + 0.2068601544100429 + -0.09063308846716889 + 0.1941437247094625 + 0.04467296204639865 + -0.1302667460292818 + -0.002833859865354921 + 0.01285906215180063 + -0.1416392433865714 + 0.2047175011079203 + -0.09382372305655916 + -0.01313767646168318 + 0.03970433934773066 + 0.1328275751432367 + 0.2134388558663492 + 0.1225627402109581 + 0.003451648640815798 + 0.1401527089620881 + -0.04527300235533499 + -0.193054067465438 + 0.1054238331143912 + 0.01788711523261599 + -0.04529521126883883 + 0.06890198380905398 + -0.05543757523542746 + -0.0101991607043735 + 0.01275825083093947 + 0.02253753243187137 + -0.1753126479363099 + -0.1147822848040538 + 0.1309585843547272 + 0.1002556185812181 + -0.2081086787839297 + 0.2116069648173263 + 0.09956651148127987 + 0.1299743320765888 + 0.4110092952243196 + 0.07041684155765403 + 0.3398905815046785 + -0.1393176371776856 + -0.06242973752869357 + -0.1127541118411364 + -0.163822215153077 + -0.07486593810902091 + -0.08925537517653959 + -0.02519462318663325 + -0.1019412998506228 + 0.07656450942853596 + 0.1009556665985779 + -0.1472375712627065 + -0.1343660250137771 + -0.07228274980292933 + -0.04125346885099707 + 0.05371791686420851 + 0.03709004327875337 + -0.02518679780258256 + 0.01816502010510537 + -0.09333116525248154 + -0.1540520976940997 + -0.009677170015297052 + 0.1086850257371473 + -0.04767224853616402 + -0.07866697277646326 + -0.1026201482532858 + -0.1248426643213241 + -0.1058664708599378 + 0.004276668663918654 + 0.07863463576625816 + 0.1989887810091926 + -0.008590536044245594 + -0.1580125299978173 + 0.06894884671352351 + -0.06498647477155509 + -0.02366813942660665 + 0.01980482410685396 + 0.06270283885924051 + -0.2245783208372042 + 0.0368732303495489 + 0.112917125763922 + 0.02303314051507049 + 0.07390193209570638 + 0.01927270918394332 + 0.003167073258190915 + -0.2345794733410854 + 0.04019276021469956 + 0.1500701266292118 + -0.1738201281370745 + -0.1746023480455238 + -0.1668196981209678 + -0.3168850573353171 + -0.1396166745089382 + 0.02248267692289839 + 0.08597907809480189 + 0.07027696815144102 + 0.06889223773757996 + 0.08333731872108889 + -0.2542789485294152 + -0.1705164795265574 + -0.1979238045369191 + 0.0092751292395125 + -0.1320156071506114 + -0.08554660199135972 + 0.1188459370298688 + 0.09836029244114676 + -0.1638474906793758 + -0.04079028244245568 + -0.04407160144056942 + 0.05152213855672327 + -0.08458460684698087 + -0.0396813083410299 + 0.1486263767638222 + 0.01916837924119908 + 0.1336541667410552 + -0.05778739849011862 + 0.2143770028388072 + -0.05090937611490887 + 0.2051024723887984 + -0.06596109921606449 + -0.03671618418312173 + -0.009633899450427197 + -0.0502357420293016 + 0.03869518548670069 + -0.06588109165496844 + -0.0002372648040582653 + -0.1344838837015011 + 0.08824977120271739 + 0.02023380208044043 + -0.2607610166480336 + -0.1896671057558585 + -0.1161377337559699 + 0.1078116990834769 + -0.2539078495142086 + 0.1390611389845949 + 0.03025764989567766 + 0.2441343358593851 + -0.06075432376952496 + 0.1638714927798439 + 0.08333511621746084 + 0.139341251156238 + 0.08122900230200247 + 0.04010435527965214 + -0.1361093194232774 + -0.009581375246758578 + 0.05835068359510442 + -0.0167803727525226 + 0.1069419995219412 + 0.07813798279419711 + 0.00305496395478661 + -0.04170405359485424 + 0.04552324600228076 + -0.1193735070676641 + -0.04913753836685447 + -0.1279944407660601 + 0.08368520759372461 + -0.0870273964516674 + 0.2925564735493265 + -0.04436631411929799 + -0.4325624868472523 + -0.2779225986835941 + -0.006550820004269859 + 0.06060604527500229 + -0.07038280030614524 + -0.08319353480795386 + 0.07136178526293338 + -0.04339465701308659 + 0.204003248326082 + -0.0009487078232958978 + 0.01870845547751275 + 0.2031705378869401 + 0.2365902766993048 + 0.06877991216878743 + 0.1016398511557229 + 0.1673681644207744 + 0.04321705461509814 + 0.07449929082525482 + 0.1817454599348936 + -0.01135984112934396 + -0.03818437913488988 + 0.1582163858452817 + 0.3811016510116187 + -0.1252250014542289 + -0.09631212562334079 + 0.01818618526493161 + -0.05960662208571994 + 0.007359280136234205 + 0.1871558156783462 + 0.07312331044671525 + -0.1456346179766477 + 0.2446716360324289 + 0.1719708917792253 + 0.01491675286930497 + 0.07521955767763136 + 0.02916786150315786 + 0.1304426167592564 + 0.03797090938346386 + 0.01617510961590824 + -0.04975631310943084 + -0.1480946570044037 + -0.02668346659829236 + 0.381378370194814 + 0.0298177070073709 + 0.1179477222364818 + -0.04400525973844824 + 0.1085493338157537 + 0.2288621661170312 + -0.2757981230185004 + -0.01523755673373449 + -0.01431038207471042 + 0.04826549588643518 + 0.05453267363123064 + -0.04269700127556757 + 0.1229262179445883 + -0.1920533368192765 + -0.09461837022106229 + 0.1426896986666275 + 0.04224060119750231 + -0.09154617518831577 + 0.06779175164874031 + 0.06389501613452804 + -0.2202272341820416 + -0.03527323064879302 + 0.05008681334841851 + 0.03915929346556274 + 0.2466306441313898 + 0.2175487276657447 + -0.0702961195826572 + -0.1133769134507895 + 0.05712035664435332 + -0.1468854598240673 + -0.008127726597428714 + -0.2111387012471612 + -0.09534085316222254 + -0.1179715420183408 + 0.07478770331190493 + -0.09543178656365206 + 0.2573332836020102 + 0.005664329361901663 + 0.1970935773063416 + 0.2555708058051488 + 0.06714732326758449 + -0.1050173840930746 + -0.03910728643028964 + -0.002382239357700849 + 0.09196459553841493 + 0.110266208869817 + 0.02425982130926525 + 0.09972451984193673 + -0.05897572466172765 + 0.0409776957910722 + 0.01919657049756203 + 0.09647129033428344 + -0.04431197213438134 + -0.05762749156366653 + -0.1347091145517745 + -0.01787318326952005 + -0.1173107653450738 + 0.09166620389002314 + 0.2033492586980972 + -0.02659322882004272 + 0.3761971232577544 + 0.1593763850604364 + -0.2074397253590146 + -0.2513758703019408 + -0.06208733697230294 + 0.1916760986268075 + 0.4126562927340601 + -0.1561244013434285 + 0.02726361886418402 + -0.06725813452732007 + 0.1911862300418384 + 0.1700206863909895 + 0.1340245065273619 + -0.05010860352551059 + 0.1391517181263541 + -0.05930793627674803 + -0.306468854568941 + -0.1765689501858524 + 0.08174207562970164 + 0.06599160790298092 + -0.03493130193206551 + 0.01347445796216553 + -0.01652733799502618 + -0.001956852260735469 + -0.04080464255465879 + -0.2103585828885884 + -0.1368458087668891 + 0.1210339853543174 + 0.1849062331186146 + -0.1678208112269515 + 0.1336501455703188 + -0.09033119301686199 + 0.1588402005151534 + 0.343835781720269 + -0.08379391991734822 + 0.2569230676782887 + -0.07074417413607342 + -0.001564406531799668 + -0.2578841033850046 + -0.153105248388453 + -0.1124828554039798 + -0.1322401275981956 + -0.04426097420023839 + -0.09413123070888091 + 0.07107967680196152 + -0.02634619189135535 + -0.2643060713405422 + -0.01763331333686636 + -0.1270950852171641 + -0.1079467603432847 + 0.1783039333682823 + 0.1207543271149685 + -0.05059305161756707 + 0.0500077937142913 + 0.009541897202125463 + -0.124412542234951 + -0.01147436953372618 + 0.07693826272523507 + 0.1620249097734542 + 0.1157966001753865 + 0.1147717935299196 + -0.08408124390959763 + -0.1293298942019157 + -0.04242673082866534 + 0.1186902819058376 + 0.2224321368384126 + 0.07696883261632403 + -0.1631116558892264 + 0.1767479567279225 + -0.07840055361446482 + 0.02839505756422219 + 0.07383972715911882 + 0.08187559519447593 + 0.04680154185353474 + -0.1435376941711448 + 0.02382519901674786 + 0.07071963415796215 + 0.1762296701831234 + -0.09299753120355189 + -0.1322024888472295 + -0.2312114558839821 + 0.02016332922095946 + 0.1035458150369197 + 0.04342529042108233 + -0.1750804855071811 + -0.3194078612121694 + 0.1141719956452492 + 0.2464973389765306 + 0.1501184810740416 + -0.09359455906567821 + -0.02378597195736246 + 0.05800560093682273 + 0.2130382320837449 + -0.05056426146108154 + -0.00822209520044149 + -0.2433323752339017 + -0.2233756383058302 + -0.2122944943525225 + -0.0952959833859832 + 0.1597547938803872 + 0.1362445073546047 + -0.05701316985566506 + -0.1461995740541905 + -0.1376034373361993 + 0.008042496278329109 + 0.03077801915443431 + 0.01444762445200487 + 0.06989371293157333 + -0.1195582098625064 + -0.0539595424483456 + -0.09423675246358731 + 0.1698144528273044 + -0.02756024565984823 + -0.2882468999634955 + -0.1311759884758881 + -0.01558802061199863 + -0.0224457616778583 + 0.02907233030836371 + -0.05395799508370444 + -0.1899445332674467 + -0.02311089430760213 + 0.007302109219061837 + 0.2752915166647281 + -0.01532451475347351 + 0.217851116547316 + -0.02338133499366784 + -0.08171995479619482 + -0.0004791226349764893 + -0.2444101439153372 + 0.1714245499183974 + -0.008866540346702038 + 0.08737048415801803 + -0.02644242953561731 + 0.1111536904065472 + 0.08042910659688406 + 0.156509008945293 + 0.09430289405471341 + -0.0173655864171539 + -0.09619637023909541 + -0.1687358810229567 + 0.104454167400238 + 0.1452731087699001 + 0.1753857178410687 + 0.04304210489835793 + 0.09367395935134991 + -0.1097771960461433 + 0.09160458976252094 + -0.1088914195400841 + -0.01385401475268408 + -0.08524650642317869 + 0.08987358524852788 + -0.155116293477577 + 0.2141486159536096 + 0.1492092829071457 + -0.2873869227907061 + -0.1694073747984203 + 0.04449343078728286 + 0.103115286333767 + 0.06288168172684462 + -0.2747744061605801 + -0.02297056591049465 + 0.08720444249778733 + 0.08394416890633438 + -0.1327623592578852 + 0.04173458743571703 + 0.152458237731526 + 0.3461122323005446 + -0.002875408825254615 + -0.03282945612781632 + 0.1320450754672017 + 0.02048398137088825 + -0.09582707087929924 + 0.2512733449041238 + 0.05158883104957444 + -0.1141932960377029 + 0.1042398783956235 + 0.4884623213804156 + -0.05533075061414328 + -0.1117222866153927 + 0.005044432789297027 + -0.05612379379222953 + 0.06294914832230025 + 0.1941755675201401 + 0.07906049237207202 + -0.1258082157852301 + 0.2708717596042585 + -0.09760234025734112 + -0.03242665155538724 + 0.1879415201850468 + 0.002820569798620299 + 0.2518511716332236 + 0.0803275582998389 + 0.03773020974465757 + -0.06680397033984264 + 0.1283608406198464 + 0.04153117115381175 + 0.2979617105798933 + -0.03793178634832229 + -0.003891166632917274 + -0.04639749128298016 + 0.1002283441790767 + 0.1168483832261361 + -0.2667430533768174 + -0.01367085281071653 + 0.1019833281797639 + 0.1039271660117523 + -0.03527621991795535 + -0.04624998419492884 + 0.2980837918314331 + -0.2854868315281638 + -0.1598720881523751 + 0.0387280564053207 + 0.03636386449609316 + 0.1232919644120742 + 0.02436843026096497 + 0.105029920398094 + -0.04958909666485345 + 0.1571536440104042 + 0.09413394319090297 + 0.02778480497282315 + 0.242970079969737 + 0.05254355219572528 + -0.1491449572648123 + -0.2470931260985709 + -0.01228434964796932 + 0.06355811607304208 + -0.01801595088186521 + -0.1910898859593492 + 0.1710955844748312 + -0.04559702767684875 + -0.0575111478414921 + -0.1488699793011382 + 0.2160837867296408 + -0.09833048311603559 + 0.2740762243973532 + 0.196460202462964 + -0.04266482443068737 + -0.2423002631251164 + 0.1866997313613146 + 0.05979064644694732 + -0.01414401353868161 + 0.08321797256258102 + -0.06857585315923068 + 0.1715112604644914 + -0.0189034493966019 + -0.07612876755441057 + -0.04571124698200564 + -0.02707626665785414 + -0.06726814877846153 + -0.07933713540823693 + -0.2232363880387216 + -0.1225110647427899 + -0.07901557311162304 + -0.2434038726792088 + 0.04182391231946075 + 0.02040372413535894 + 0.2642931236104718 + 0.065054883743249 + -0.1934153114319666 + -0.1062764570509464 + 0.01285726935331507 + -0.06215941491929874 + 0.1678446925262784 + -0.09865782692429458 + 0.07530151382627132 + -0.1013625340775283 + 0.009583628919469565 + 0.08935997037860935 + 0.001550289089127295 + -0.07335378231021988 + 0.02747888374533144 + -0.05307225774444272 + -0.225229891765628 + -0.2466469657963566 + 0.0622060053526241 + -0.01521296570200277 + -0.1970300499474153 + 0.1215176040584392 + 0.03322006227892838 + -0.04844281483073029 + -0.08415868964479693 + -0.2851960309152597 + -0.02841991724320317 + 0.004328912759733721 + 0.1294844674217196 + 0.02323963952147449 + -0.08702828184693133 + -0.1455058609075093 + 0.1995832547453136 + -0.0963625077337103 + -0.1375888779685707 + -0.005097603978441743 + -0.0871715942930449 + 0.2948677723918121 + -0.1961953557700017 + 0.05063085134576723 + -0.05485224718210201 + -0.02511095975751573 + 0.0738554145551166 + -0.09901626591372396 + 0.06946042014560544 + -0.07429564005875608 + -0.2455272837770868 + 0.03372532696013532 + -0.08439936125553943 + -0.1572832469890588 + 0.1421293893193454 + 0.1350828196257556 + 0.01284495548336082 + 0.02401257811824288 + 0.2376645902786213 + -0.04768422021523566 + 0.008506985254358865 + 0.09221586488938285 + 0.1594568175859658 + 0.2398227844303611 + 0.2217887753200039 + -0.01367038094914552 + -0.06609246442513816 + -0.2536997173938265 + 0.08045561624986598 + 0.1193326939600289 + 0.04853212560949158 + -0.04788513564622857 + 0.09820725089378556 + 0.01490145766813217 + 0.09373763915343922 + 0.0897072289251121 + 0.09499907894080312 + 0.272505682209672 + -0.2857589771181943 + 0.005304615118724173 + 0.05316934366000153 + 0.01670147793074279 + -0.1685523439260301 + -0.1047253643943811 + -0.2014958780552916 + -0.01753126891589298 + 0.04638300742964078 + 0.1865532167008373 + -0.1041550692098078 + -0.2857638552509695 + -0.8394358504816395 + 0.3330390755443413 + 0.173604750818609 + -0.1949895278003864 + -0.11034922746134 + 0.08305215006310965 + 0.1910586669010612 + 0.0624507135870807 + 0.2033769226006744 + -0.1332893388753211 + -0.1665040500810019 + -0.1583995945363945 + -0.0928760555111864 + 0.1046645926228185 + 0.08948613255992462 + 0.1390079420677361 + -0.1168928404998971 + -0.1222877571044974 + 0.02071735304784578 + 0.06101889198176324 + 0.04341097822694753 + -0.1040487411973801 + -0.1930880413023381 + -0.2651315941018598 + -0.06857898767141712 + 0.04354947542368268 + 0.06072415507640783 + -0.2081057198639228 + -0.1170660072676494 + 0.06315832519668199 + -0.01618372455765315 + -0.06229440929331015 + -0.1567795831060125 + -0.139993917471725 + 0.06967841651494464 + -0.01157645040402994 + 0.2714731163939807 + -0.09094984260662788 + 0.1715229016506518 + 0.1123678629388844 + -0.0953055252276355 + -0.2378751782795372 + 0.01218028128948376 + 0.1417061355775053 + -0.09060031938931913 + 0.03143406610038076 + 0.06406970945828171 + 0.00789120192992214 + 0.08503060820804119 + 0.06586642608064781 + 0.01501737721700442 + -0.05287204124357602 + -0.04459814410608586 + -0.2643918429045177 + 0.08606248389917648 + 0.2163985425078364 + 0.2084730316286358 + -0.009923413481752378 + 0.1376473206377184 + -0.1256474104629678 + 0.1797438248182083 + -0.0528458399648412 + 0.06226020372455229 + 0.007729067427583284 + -0.08258941472058653 + -0.1016452553720866 + -0.003163777303716113 + 0.1406984451120088 + 0.06031349150870733 + -0.03691463724772255 + 0.105088024901643 + 0.02358620124652299 + 0.1201299972636165 + -0.3475476490803814 + -0.0742841930401084 + 0.198497449725175 + -0.0633362323960646 + -0.1966852856580519 + 0.08521942360899989 + 0.1506537818464838 + 0.2114699598939301 + -0.01776267690472441 + -0.04440858070327856 + 0.003079306746925076 + 0.007120375745703148 + -0.217518055554508 + 0.2750843488415229 + 0.03434634955464149 + -0.1756095706398672 + 0.03544462957076241 + 0.4709577299861736 + -0.02746333873121611 + -0.08733991476199504 + 0.04348846502484977 + -0.02695563459697091 + 0.1007257842131707 + 0.2036253770829468 + 0.05487190823942002 + 0.05536619806041074 + 0.131265496918509 + -0.2545897950563981 + -0.1813137866248553 + 0.1644956298879932 + 0.03406397304977367 + 0.2742647458265721 + 0.03612786816975609 + 0.05366755624078459 + -0.002242693382883745 + 0.3077909261259039 + 0.07480294633403545 + 0.1038367356579036 + -0.05317065623529878 + -0.03449087402103904 + 0.06688730844735781 + -0.02575597697681738 + 0.03044747743062777 + -0.1353819500594901 + 0.002417498432139633 + 0.1101825131866615 + 0.0919828128933208 + -0.1439948250968756 + -0.1047273023889282 + 0.166282388944002 + -0.2020929261190566 + -0.107451519642646 + -0.05634226151267367 + -0.01853034273477917 + 0.1817293184379292 + -0.003283480805546549 + 0.03667594122847624 + -0.06916593471154825 + 0.307169001970326 + 0.02469560769794513 + 0.09469772985034791 + 0.1867527749713585 + -0.1230908802114091 + -0.1909553472482549 + -0.2204450052591909 + -0.07092543100988956 + 0.2294652216754263 + 0.03816382623221562 + -0.009400920012224982 + 0.1915875431217992 + 0.01820930314708271 + -0.0619969906367219 + -0.1565322933149482 + 0.1157588638822702 + -0.1751806538241918 + 0.2295575250339776 + -0.05884628955432975 + -0.1097375186682496 + -0.1781749429765534 + 0.2162688496726471 + 0.0225355614780918 + -0.07849648776723586 + -0.01547965292772258 + -0.1153197350031277 + 0.07895824076700365 + 0.05065324858367866 + -0.1085494286285821 + -0.0379692199225021 + -0.09879446437686498 + -0.1253687360897433 + -0.04399958723243259 + -0.1327717233439862 + -0.1891844271346936 + 0.1365897278433574 + -0.4072177659113166 + -0.1423190421710968 + 0.002569210771690537 + 0.2874981836456109 + -0.0451481065719694 + -0.1254153236881238 + 0.1173968851598019 + 0.02373553294657881 + 0.3662965379428074 + 0.3346136570276884 + -0.05717662342641277 + 0.03293252356079885 + -0.02784304467878897 + -0.09214284097721631 + -0.002668431416544305 + -0.1347840225293861 + -0.03883720970638058 + 0.0002532185932718686 + -0.04818120634933561 + -0.2334561183354495 + -0.1592639424552839 + 0.02857859370708266 + -0.1001967303563061 + -0.1363043656655723 + 0.1162742307337141 + 0.06110858262281978 + -0.04375289436171732 + 0.0002603326247158308 + -0.2556094979182465 + 0.001616731568954928 + -0.04893769491895026 + 0.0963305594616868 + 0.1536209272985045 + -0.1935464003918078 + -0.09095698386345863 + 0.1534695823746832 + -0.2571331879374995 + -0.03247827224784545 + -0.2176747306769753 + -0.08464400767846247 + 0.369657359737719 + -0.02603595411742499 + 0.1063412520548481 + 0.004150612307143683 + 0.1239008337604071 + 0.1628892741047316 + -0.07768359672987041 + 0.06108909165579486 + 0.003405857181209642 + -0.07765376042059041 + 0.003320485950160026 + -0.01086861632902177 + -0.122078218606576 + 0.02393691286549908 + 0.06713997366639572 + 0.08898611607835161 + -0.02379243913273671 + 0.2949912814331299 + 0.1350614374648974 + 0.04881340104260548 + 0.1313005175892898 + -0.05043049072684099 + 0.1997599225730803 + 0.1331853724035849 + 0.03310678334263119 + -0.09492731892301552 + 0.03823474521755243 + -0.004415351525256783 + 0.112180980330195 + -0.03234104256631049 + 0.1472018282967266 + -0.09018514576631975 + 0.07544746126523917 + 0.1166113632468761 + 0.08275494188757555 + 0.07278778610114685 + 0.2597969514123001 + -0.1841205434537519 + 0.06788021895957397 + 0.002852335989421522 + -0.2493773200438772 + -0.1500862029925856 + 0.03890592159244441 + -0.07527513568205077 + -0.0309070538452651 + -0.0298841983279069 + 0.1440875574115637 + -0.05018906262328114 + -0.06025221539547261 + 0.21401768860684 + 0.1493930142401384 + 0.1333652585828323 + -0.1644513860689316 + -0.1073181293398727 + 0.1917320319030454 + 0.04211720043513827 + -0.03325617410057424 + 0.2358847962085744 + -0.05531576552570384 + 0.05270157556976172 + -0.02204619127250945 + -0.05606127005459256 + 0.02982912792683756 + -0.02712518468388254 + 0.2952018668094087 + -0.009964997687088591 + -0.03046183918404762 + 0.04857529176171757 + 0.03043983288723968 + 0.01194376398546001 + -0.2067805618562731 + -0.1427842314855997 + -0.2869698997130766 + -0.01754440457903484 + -0.1189582216535462 + 0.2111332403638705 + -0.03105682135869399 + -0.04749585051152591 + 0.0946820396112875 + -0.02623963438519194 + -0.2913698748998487 + -0.2527033466974923 + -0.01292672680845454 + 0.167227040710764 + -0.1118497216760054 + 0.1373157790798296 + -0.1064750291744089 + 0.25052084295729 + 0.02332718041178225 + -0.07064340503825219 + -0.3456836491069989 + 0.1611961252647666 + 0.08760562437004332 + -0.1662756750750775 + 0.0526247766559812 + 0.02529274647444501 + -0.09326957765490271 + 0.03959060965422974 + -0.1348052647751649 + -0.1002186676596551 + -0.01269827705926385 + -0.02411956016849976 + -0.262654857829906 + 0.02634585573229658 + 0.03059574017434615 + 0.1334453440583568 + -0.1095658904969446 + 0.1653660058320955 + -0.1136809261605006 + 0.1428038840878058 + -0.05498598280404418 + 0.2294913039841647 + 0.03080683617387336 + -0.3096504146489982 + 0.05558356921026913 + -0.2264985011241068 + 0.03556299064781845 + 0.3678144671983024 + 0.0751761179683321 + 0.08152764270123794 + -0.06493472510581649 + 0.1304829098615351 + -0.1963527938965993 + -0.07529733889630785 + 0.1800076492009783 + -0.1542377218219825 + -0.1451314883212949 + 0.08344166652972178 + 0.05291208484804868 + -0.007913258494954755 + -0.03039124200121655 + 0.04152829385599959 + -0.07994400191575796 + -0.02694551195409341 + -0.2792023304016716 + 0.182922872568378 + -0.04793443758820662 + -0.1988501180364287 + -0.02313241602466044 + 0.3806790349750098 + -0.1087354764359422 + -0.0235633636573383 + 0.05543209692211608 + -0.01119442471601603 + 0.1495509220089313 + 0.1731985277075746 + 0.02608732062190484 + 0.2286027832429134 + -0.06109695995265021 + -0.2236285563540323 + -0.1926920427073123 + -0.03794520281908435 + 0.1075356138273536 + 0.1363843578238267 + 0.05236801337224944 + 0.07315242602667636 + 0.09120667067391078 + 0.2673917413667651 + -0.04928426751819683 + -0.1242584633656258 + -0.07351478269641104 + 0.003555001656605677 + 0.1865312501760474 + -0.2478980546448966 + 0.03891423303705837 + 0.09271232658029689 + 0.09990992167686555 + 0.04975465166628711 + 0.06237688864617102 + -0.1618745567144718 + -0.2072815728074243 + 3.24320887345834e-05 + -0.009324489084374568 + 0.02516269431032846 + -0.05100859800583433 + -0.0671930965950919 + -0.02951213277188766 + -0.06777233683864496 + -0.09339641768732099 + -0.1972348870531456 + 0.3439146165567926 + -0.04434332484378644 + 0.2407616698867662 + 0.07362486219683421 + -0.2782920205084793 + -0.0877032592308811 + -0.06949037920661379 + -0.05722336869839895 + 0.3020109799810665 + 0.1845736443705813 + 0.1639268362941793 + 0.0007454141494778137 + 0.1011307220756484 + 0.05352505760522216 + -0.1124356121406138 + -0.006314398380578822 + -0.1817709975861904 + 0.07690033839008623 + -0.06109448276466303 + -0.1022404490233799 + -0.02667620582706734 + 0.09629110625137843 + -0.02431260261297468 + -0.07644195566754071 + -0.1186587514424158 + -0.1011749903692891 + -0.1564408651720882 + 0.08805601365843475 + -0.07064913600645135 + -0.02635840998600408 + -0.1078314746964917 + -0.1709695145951056 + 0.01479845069411982 + -0.01381638575244491 + -0.1550512932185826 + 0.2503777385827729 + -0.2390248644176812 + -0.2883893597409654 + -0.06181291307901987 + 0.1582364175796699 + -0.02312071621553637 + 0.00217638563547544 + 0.3237854977363662 + -0.03252544620611295 + 0.003750133894739771 + 0.009671642707881114 + -0.009497472747113498 + 0.07116666910192301 + 0.08816537960315252 + -0.06363471414932657 + -0.09448929109059846 + -0.1838435758631711 + 0.03492670834095708 + 0.04311774220442871 + 0.01678837491608537 + -0.08551317416391886 + 0.01579603526355288 + 0.04714940819834743 + -0.06812683188087337 + 0.04021687008946623 + 0.06658770294854371 + 0.04200650408334704 + 0.02648272347175153 + 0.1171065218544724 + -0.1580241793274017 + -0.04345466645506941 + -0.05306499481440482 + 0.07072616774249532 + 0.2393715380477287 + -0.1142803782761256 + 0.007919304164271446 + 0.03903245447045534 + -0.1972537874679361 + 0.1808024692666788 + -0.1496471578524902 + -0.03601188242560322 + 0.2450678955523587 + 0.1267384878365154 + -0.01909164755778832 + 0.01601852906118508 + + diff --git a/codec2/branches/0.7/octave/vq_pager.m b/codec2/branches/0.7/octave/vq_pager.m new file mode 100644 index 00000000..f00de9e5 --- /dev/null +++ b/codec2/branches/0.7/octave/vq_pager.m @@ -0,0 +1,47 @@ +% vq_pager.m +% +% Interactive Octave script to inspect vectors, e.g. for newamp1.m vector quantisation +% +% Usage: +% +% octave:14> vq_pager(vq) + +function vq_pager(vq) + grid_sz = 4; + + [vq_rows vq_cols] = size(vq); + + r = 1; + + % Keyboard loop + + k = ' '; + do + figure(1); clf; + n_plot = min(grid_sz*grid_sz,vq_rows-r+1) + printf("r: %d n_plot: %d\n", r, n_plot); + for i = 1:n_plot; + subplot(grid_sz,grid_sz,i); + plot(vq(r+i-1,:)); + axis([1 vq_cols -20 20]); + end + + % interactive menu + + printf("\rr: %d menu: n-next b-back q-quit", r); + fflush(stdout); + k = kbhit(); + + if k == 'n' + r = r + grid_sz*grid_sz; + r = min(r, vq_rows); + endif + if k == 'b' + r = r - grid_sz*grid_sz; + r = max(r,1); + endif + until (k == 'q') + printf("\n"); + +endfunction + diff --git a/codec2/branches/0.7/octave/xormixer.m b/codec2/branches/0.7/octave/xormixer.m new file mode 100644 index 00000000..c8caf79b --- /dev/null +++ b/codec2/branches/0.7/octave/xormixer.m @@ -0,0 +1,37 @@ +% xormixer.m +% David Rowe Sep 2015 +% +% Testing xor gate as a mixer for constant amplitude +% modulation schemes + +n = 1024; +carrier = modulation = zeros(1,n); + +Tc = 4; % carrier period +for i=1:Tc:n + carrier(i:i+Tc/2-1) = 1; +end + +Tm = 32; % modulation signal period +for i=1:Tm:n + modulation(i:(i+Tm/2-1)) = 1; +end + +%carrier = carrier .* hanning(n)'; +%modulation = modulation .* hanning(n)'; +mixer = xor(carrier,modulation) .* hanning(n)'; + +figure(1); +clf +subplot(311) +plot(abs(fft(carrier))) +axis([1 n 0 n/2]); + +subplot(312) +plot(abs(fft(modulation))) +axis([1 n 0 n/2]); + +subplot(313) +plot(abs(fft(mixer))) +axis([1 n 0 n/2]); + diff --git a/codec2/branches/0.7/octave/yafsk.m b/codec2/branches/0.7/octave/yafsk.m new file mode 100644 index 00000000..d38169c9 --- /dev/null +++ b/codec2/branches/0.7/octave/yafsk.m @@ -0,0 +1,664 @@ +% yafsk.m +% Yet-another-FSK +% Brady O'Brien 20 October 2015 +% +% This is a model for the first attempt at a C FSK modem. Based on fsk_horus and maybe a little fsk4. +% First revision will just be 2fsk +% [x] - Modem init and struct def +% [x] - Direct SDR modulator, probably not FM based +% [x] - Direct SDR non-coherent demodulator +% [x] - Core demodulation routine +% |o| - Timing offset estimation +% < >- Freq. offset estimation +% (+) - Bit slip, maybe +% { } - Port sim from fsk_horus +% [ ] - The C port +% [ ] - Some stuff to verify the C port +% [ ] - 4FSK variant +% ( ) - All of that other stuff, but for 4fsk +%clear all; + +graphics_toolkit('gnuplot'); +%fm + +pkg load signal; + +%Basic parameters for a simple FSK modem +fsk_setup_info.Rs = 4800; % Symbol rate +fsk_setup_info.nfsk = 2; % Number of unique symbols. Must be 2. +fsk_setup_info.P = 5; %Something something fine timing est +fsk_setup_info.Fs = 48000; % Sample frequency +fsk_setup_info.timing_syms = 10; %How many symbols over which to figure fine timing +fsk_setup_info.Fsym = fsk_setup_info.Rs; %Symbol spacing +fsk_setup_info.txmap = @(bits) bits+1; %Map TX bits to 2fsk symbols +fsk_setup_info.rxmap = @(syms) syms==1; %Map 2fsk RX symbols to bits +global fsk_setup = fsk_setup_info + +function states = yafsk_init(fsk_config) + Fs = states.Fs = fsk_config.Fs; + Rs = states.Rs = fsk_config.Rs; + nfsk = states.nfsk = fsk_config.nfsk; + Ts = states.Ts = Fs/Rs; + Fsym = states.Fsym = fsk_config.Fsym; + states.config = fsk_config; + P = states.P = fsk_config.P; + timing_syms = states.timing_syms = fsk_config.timing_syms; + + if nfsk != 2 + error("Gotta be 2fsk") + endif + + %Symbol frequencies. Fixed to intervals of Fsym. + states.fsyms = [-(Fsym/2) (Fsym/2)]; + states.tx_phase = 0; + + states.dc = zeros(1,nfsk); + states.rx_phi = ones(1,nfsk); + states.isamp = 0; + states.ssamp = 0; + states.sums = zeros(1,nfsk); + states.ssums = zeros(1,nfsk); + timing_db1 = timing_db2 = zeros(1,timing_syms*(Ts/P)) + states.timing_db1 = timing_db1; + states.timing_db2 = timing_db2; +endfunction + +function [tx states] = yafsk_mod(states,bits) + Ts = states.Ts; + Fs = states.Fs; + fsyms = states.fsyms; + tx_phase = states.tx_phase; + %Map bits into symbols + syms = states.config.txmap(bits); + tx = zeros(1,Ts*length(syms)); + + for ii = (1:length(syms)) + cur_sym_f = fsyms(syms(ii)); + tx_phase_i = tx_phase; + for jj = (1:Ts) + tx_phase_i = tx_phase + jj*2*pi*cur_sym_f/Fs; + tx((ii-1)*Ts+jj) = exp(j*tx_phase_i); + end + tx_phase = tx_phase + Ts*2*pi*cur_sym_f/Fs; + if tx_phase>2*pi + tx_phase = tx_phase-2*pi; + elseif tx_phase<-2*pi + tx_phase = tx_phase+2*pi; + endif + %tx_phase_vec = tx_phase + (1:Ts)*2*pi*cur_sym_f/Fs; + %tx((ii-1)*Ts+1:ii*Ts) = exp(j*tx_phase_vec); + end + states.tx_phase = tx_phase; +endfunction + +function d = idmp(data, M) + d = zeros(1,length(data)/M); + for i = 1:length(d) + d(i) = sum(data(1+(i-1)*M:i*M)); + end +endfunction + +function [bits states phis softsyms] = yafsk_demod_2a(states,rx) + fine_timing = 1; + Fs = states.Fs; + Rs = states.Rs; + Ts = states.Ts; + nfsk = states.nfsk; + P = 5; + + + phy_f1 = states.rx_phi(1); + phy_f2 = states.rx_phi(2); + + dphase_f1 = exp(states.fsyms(1)*-j*2*pi/Fs); + dphase_f2 = exp(states.fsyms(2)*-j*2*pi/Fs); + + sum_f1 = states.sums(1); + sum_f2 = states.sums(2); + + ssum_f1 = states.ssums(1); + ssum_f2 = states.ssums(2); + + timing_db1 = states.timing_db1; + timing_db2 = states.timing_db2; + + ssamp = states.ssamp; + isamp = states.isamp; + + symcnt = 1; + subcnt = 1; + syms = [0]; + softsyms = [0]; + sums1 = [0]; + sums2 = [0]; + phis = [0]; + isamp = 1; + isub = 1; + + ssum_f1 = 0; + ssum_f2 = 0; + ssamp=0; + + timing_syms = states.timing_syms; + timing_nudge = .09; %How far to 'nudge' the sampling point + %This really ought to be fixed somewhere else + + timing_samps = timing_syms*(Ts/P); + + for ii = (1:length(rx)) + phy_f1 *= dphase_f1; %Spin the oscillators + phy_f2 *= dphase_f2; + + dcs_f1 = rx(ii)*phy_f1; %Figure out the DC + dcs_f2 = rx(ii)*phy_f2; + + sum_f1 += dcs_f1; %Integrate + sum_f2 += dcs_f2; + ssum_f1 += dcs_f1; + ssum_f2 += dcs_f2; + + + %Frequency of timing tracking nonlinearity + w = (2*pi*Rs)/(Rs*P); + + %increment symbol and timing sub-loop counters + ssamp += 1; + isamp += 1; + if isamp>=Ts %If it's time to take a sample and spit out a symbol.. + syms(symcnt) = (abs(sum_f1)>abs(sum_f2))+1; %Spit out a symbol + softsyms(symcnt) = abs(sum_f1) - abs(sum_f2); + symcnt += 1; + + %Fine timing estimation and adjustment + %Re-integrate over entire symbol peiod and apply nonlinearity + %To-do - rewrite in more c-able loop + timing_phi = 0; + for jj=(1:(length(timing_db1)-P)) + f1 = sum(timing_db1(jj:jj+P)); + f2 = sum(timing_db2(jj:jj+P)); + tdmd = (abs(f1)-abs(f2))^2; + timing_phi += tdmd*exp(-j*w*jj); + end + + %Take angle of nonlinear spectral line + timing_phi = angle(timing_phi); + %get another number + norm_phi = timing_phi/(2*pi); + norm_timing = norm_phi*P; + + %Ideal fine timing point, determined experimentally + norm_tgt = -1.37; + + %move sampling point a bit forward or backward + if(norm_timing>norm_tgt && norm_timing= (Ts/P) + + %save timing samples + timing_db1(1:timing_samps-1)=timing_db1(2:timing_samps); + timing_db1(timing_samps) = ssum_f1; + timing_db2(1:timing_samps-1)=timing_db2(2:timing_samps); + timing_db2(timing_samps) = ssum_f2; + + + %Reset integrators and sampling counter + ssum_f1 = 0; + ssum_f2 = 0; + ssamp -= Ts/P; + endif + + end + + states.rx_phy(1) = phy_f1; + states.rx_phy(2) = phy_f2; + + states.sums(1) = sum_f1; + states.sums(2) = sum_f2; + + states.ssum(1) = ssum_f1; + states.ssum(2) = ssum_f2; + + states.ssamp = ssamp; + states.isamp = isamp; + + states.timing_db1 = timing_db1; + states.timing_db2 = timing_db2; + + bits = states.config.rxmap(syms); + + +endfunction + + +function [bits states] = yafsk_demod_2(states,rx) + fine_timing = 1; + Fs = states.Fs; + Rs = states.Rs; + Ts = states.Ts; + nfsk = states.nfsk; + + rx = rx(fine_timing:length(rx)); + sym_phases = (1:length(rx)).*rot90(states.fsyms)*2*pi/Fs; + + sym_mixers = exp(-j*sym_phases); + rx_mixd = repmat(rx,nfsk,1).*sym_mixers; + + dc1 = abs(idmp(rx_mixd(1,1:length(rx_mixd)),Ts)); + dc2 = abs(idmp(rx_mixd(2,1:length(rx_mixd)),Ts)); + + t=(1:length(dc1)); + + plot(t,dc1,t,dc2) + +endfunction + +% Simulation thing, shamelessly taken from fsk_horus.m +% simulation of tx and rx side, add noise, channel impairments ---------------------- + +function run_sim + global fsk_setup; + frames = 10; + EbNodB = 26; + timing_offset = 0.0; % see resample() for clock offset below + test_frame_mode = 2; + fading = 0; % modulates tx power at 2Hz with 20dB fade depth, + % to simulate balloon rotating at end of mission + df = 0; % tx tone freq drift in Hz/s + + more off + rand('state',100); + randn('state',100); + states = yafsk_init(fsk_setup); + N = states.N; + %P = states.P; + Rs = states.Rs; + nsym = states.nsym = 4096; + Fs = states.Fs; + states.df = df; + + EbNo = 10^(EbNodB/10); + variance = states.Fs/(states.Rs*EbNo); + + % set up tx signal with payload bits based on test mode + + if test_frame_mode == 1 + % test frame of bits, which we repeat for convenience when BER testing + test_frame = round(rand(1, states.nsym)); + tx_bits = []; + for i=1:frames+1 + tx_bits = [tx_bits test_frame]; + end + end + if test_frame_mode == 2 + % random bits, just to make sure sync algs work on random data + tx_bits = round(rand(1, states.nsym*(frames+1))); + end + if test_frame_mode == 3 + % ...10101... sequence + tx_bits = zeros(1, states.nsym*(frames+1)); + tx_bits(1:2:length(tx_bits)) = 1; + end + + if test_frame_mode == 4 + + % load up a horus msg from disk and modulate that + + test_frame = load("horus_msg.txt"); + ltf = length(test_frame); + ntest_frames = ceil((frames+1)*nsym/ltf); + tx_bits = []; + for i=1:ntest_frames + tx_bits = [tx_bits test_frame]; + end + end + + tx = yafsk_mod(states, tx_bits); + + %tx = resample(tx, 1000, 1001); % simulated 1000ppm sample clock offset + + if fading + ltx = length(tx); + tx = tx .* (1.1 + cos(2*pi*2*(0:ltx-1)/Fs))'; % min amplitude 0.1, -20dB fade, max 3dB + end + + noise = sqrt(variance)*randn(length(tx),1); + rx = tx + noise; + + % dump simulated rx file + ftx=fopen("ya_fsk_rx.raw","wb"); rxg = rx*1000; fwrite(ftx, rxg, "short"); fclose(ftx); + + timing_offset_samples = round(timing_offset*states.Ts); + st = 1 + timing_offset_samples; + rx_bits_buf = zeros(1,2*nsym); + Terrs = Tbits = 0; + state = 0; + x_log = []; + norm_rx_timing_log = []; + nerr_log = []; + f1_int_resample_log = []; + f2_int_resample_log = []; + f1_log = f2_log = []; + EbNodB_log = []; + rx_bits_log = []; + rx_bits_sd_log = []; + + for f=1:frames + + % extract nin samples from input stream + + nin = states.nin; + en = st + states.nin - 1; + sf = rx(st:en); + st += nin; + + % demodulate to stream of bits + + [rx_bits states] = yafsk_demod(states, sf); + rx_bits_buf(1:nsym) = rx_bits_buf(nsym+1:2*nsym); + rx_bits_buf(nsym+1:2*nsym) = rx_bits; + rx_bits_log = [rx_bits_log rx_bits]; + rx_bits_sd_log = [rx_bits_sd_log states.rx_bits_sd]; + + norm_rx_timing_log = [norm_rx_timing_log states.norm_rx_timing]; + x_log = [x_log states.x]; + f1_int_resample_log = [f1_int_resample_log abs(states.f1_int_resample)]; + f2_int_resample_log = [f2_int_resample_log abs(states.f2_int_resample)]; + f1_log = [f1_log states.f1]; + f2_log = [f2_log states.f2]; + EbNodB_log = [EbNodB_log states.EbNodB]; + + % frame sync based on min BER + + if test_frame_mode == 1 + nerrs_min = nsym; + next_state = state; + if state == 0 + for i=1:nsym + error_positions = xor(rx_bits_buf(i:nsym+i-1), test_frame); + nerrs = sum(error_positions); + if nerrs < nerrs_min + nerrs_min = nerrs; + coarse_offset = i; + end + end + if nerrs_min < 3 + next_state = 1; + %printf("%d %d\n", coarse_offset, nerrs_min); + end + end + + if state == 1 + error_positions = xor(rx_bits_buf(coarse_offset:coarse_offset+nsym-1), test_frame); + nerrs = sum(error_positions); + Terrs += nerrs; + Tbits += nsym; + nerr_log = [nerr_log nerrs]; + end + + state = next_state; + end + end + + if test_frame_mode == 1 + printf("frames: %d Tbits: %d Terrs: %d BER %4.3f\n", frames, Tbits, Terrs, Terrs/Tbits); + end + + if test_frame_mode == 4 + extract_and_print_packets(states, rx_bits_log, rx_bits_sd_log) + end + + figure(1); + plot(f1_int_resample_log,'+') + hold on; + plot(f2_int_resample_log,'g+') + hold off; + + figure(2) + clf + m = max(abs(x_log)); + plot(x_log,'+') + axis([-m m -m m]) + title('fine timing metric') + + figure(3) + clf + subplot(211) + plot(norm_rx_timing_log); + axis([1 frames -1 1]) + title('norm fine timing') + subplot(212) + plot(nerr_log) + title('num bit errors each frame') + + figure(4) + clf + plot(real(rx(1:Fs))) + title('rx signal at demod input') + + figure(5) + clf + plot(f1_log) + hold on; + plot(f2_log,'g'); + hold off; + title('tone frequencies') + axis([1 frames 0 Fs/2]) + + figure(6) + clf + plot(EbNodB_log); + title('Eb/No estimate') + +endfunction + +% Bit error rate test ---------------------------------------------------------- +% Params - aEsNodB - EbNo in decibels +% - timing_offset - how far the fine timing is offset +% - bitcnt - how many bits to check +% - demod_fx - demodulator function +% Returns - ber - teh measured BER +% - thrcoh - theory BER of a coherent demod +% - thrncoh - theory BER of non-coherent demod +function [ber thrcoh thrncoh rxphis] = nfbert_2(aEsNodB,modem_config, bitcnt=12000, timing_offset = 1, freq_offset = 0, burst = 0,samp_clk_offset = 0) + + rand('state',1); + randn('state',1); + + %How many bits should this test run? + %bitcnt = 12000; + + framesync = [] + framehdr = [1 0 1 0 1 0 1 0 0 1 1 1 0 1 0 0] + convhdr = framehdr;%[.5 -.5 .5 -.5 1 -1 1 -1 -1 1 1 1 -1 1 -1 -1]; + %framehdr = [1 0 1 0 0 0 1 0 1 0 0 1] + test_bits = [framesync framehdr (rand(1,bitcnt)>.5)]; %Random bits. Pad with zeros to prime the filters + states.M = 1; + states = yafsk_init(modem_config); + + %Set this to 0 to cut down on the plotting + states.verbose = 1; + Fs = states.Fs; + Rb = states.Rs; % Multiply symbol rate by 2, since we have 2 bits per symbol + + tx = yafsk_mod(states,test_bits); + + tx = resample(tx, 1000, 1000 + samp_clk_offset); + + %simulate a single frame in a pool of noise + if(burst) + tx = [zeros(1,Fs/2) tx zeros(1,Fs/2)]; + end + + + %add noise here + %shamelessly copied from gmsk.m + EsNo = 10^(aEsNodB/10); + EbNo = EsNo + variance = Fs/(Rb*EbNo); + nsam = length(tx); + noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam)); + rx = tx*exp(j*pi/2) + noise; + t = (1:length(rx)); + rx = rx .* exp(t*2*pi*j*(freq_offset/Fs)); + + rx = rx(timing_offset:length(rx)); + + [rx_bits states rxphis sbits] = yafsk_demod_2a(states,rx); + + + ber = 1; + + hsig = -1*fliplr((framehdr*2)-1); + figure(3); + corrfd = conv(hsig,sbits); + for ii = (1:length(corrfd)-length(hsig)) + secte = sum(abs(sbits(ii:ii+length(hsig))).^2); + corrfd = corrfd(ii)/secte; + end + %thing to account for offset from input data to output data + %No preamble detection yet + figure(4); + plot(rxphis); + ox = 1; + + if(burst) + orange = (1:length(rx_bits)-length(test_bits)-1); + else + orange = (1:100) + end + for offset = orange + if(burst) + perr = xor(test_bits,rx_bits(offset:offset-1+length(test_bits))); + nerr = sum(perr); + bern = nerr / length(test_bits); + else + perr = xor(test_bits(offset:length(rx_bits)),rx_bits(1:length(rx_bits)+1-offset)); + nerr = sum(perr); + bern = nerr/(bitcnt-offset); + end + + if(bern < ber) + ox = offset; + best_nerr = nerr; + xerr = perr; + end + ber = min([ber bern]); + end + + %Try to find frame header + for offset = (1:length(rx_bits)-length(framehdr)) + hd = sum(xor(framehdr,rx_bits(offset:offset-1+length(framehdr)))); + if(hd<=2) + printf("Found possible header at offset %d\n",offset); + endif + end + + figure(5); + stairs(1.0*xerr); + + offset = ox; + printf("\ncoarse timing: %d nerr: %d\n", offset, best_nerr); + + % Coherent BER theory + thrcoh = .5*erfc(sqrt(.5*EbNo)); + + % non-coherent BER theory calculation + % It was complicated, so I broke it up + + ms = 2; + ns = (1:ms-1); + as = (-1).^(ns+1); + bs = (as./(ns+1)); + + cs = ((ms-1)./ns); + + ds = ns.*log2(ms); + es = ns+1; + fs = exp( -(ds./es)*EbNo ); + + thrncoh = ((ms/2)/(ms-1)) * sum(bs.*((ms-1)./ns).*exp( -(ds./es)*EbNo )); + +endfunction + + +function rxphi = fine_ex(timing_offset = 1,fsk_info) + + rand('state',1); + randn('state',1); + + bitcnt = 12051; + test_bits = [zeros(1,100) rand(1,bitcnt)>.5]; %Random bits. Pad with zeros to prime the filters + t_vec = [0 0 1 1]; + %test_bits = repmat(t_vec,1,ceil(24000/length(t_vec))); + + states = yafsk_init(fsk_info); + Fs = states.Fs; + Rb = states.Rs; + + tx = yafsk_mod(states,test_bits); + + rx = tx; + rx = rx(timing_offset:length(rx)); + + [rx_bits states rxphi] = yafsk_demod_2a(states,rx); + ber = 1; + + %thing to account for offset from input data to output data + %No preamble detection yet + ox = 1; + for offset = (1:100) + nerr = sum(xor(rx_bits(offset:length(rx_bits)),test_bits(1:length(rx_bits)+1-offset))); + bern = nerr/(bitcnt-offset); + if(bern < ber) + ox = offset; + best_nerr = nerr; + end + ber = min([ber bern]); + end + offset = ox; + printf("\ncoarse timing: %d nerr: %d\n", offset, best_nerr); + +endfunction + +function phi=fine_2(aEsNodB,fsk_info,bits,offset,freq) + [ber coh ncoh phi] = nfbert_2(aEsNodB,fsk_info, bits, offset, freq) +endfunction + +function yafsk_rx_phi + global fsk_setup + pkg load parallel + offrange = [1:2:101]; + + setups = repmat(fsk_setup,1,length(offrange)); + phi = pararrayfun(nproc(),@fine_2,100,setups,1,offrange,0*ones(1,length(offrange))); + + close all; + figure(1); + clf; + plot(offrange,real(phi),offrange,imag(phi)); + figure(2); + plotyy(offrange,angle(phi),offrange,abs(phi)) +endfunction + diff --git a/codec2/branches/0.7/raw/b0067.raw b/codec2/branches/0.7/raw/b0067.raw new file mode 100644 index 0000000000000000000000000000000000000000..3aea9cdaaa2d6c9f09669e866350585929f6fd18 GIT binary patch literal 58482 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�bkW`Z&<9pReiZ)T3JDHa8c*NYlTw_ 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 R)J9Vcm`%JaHoNsa{eMo!x*Grh literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/cq_ref.raw b/codec2/branches/0.7/raw/cq_ref.raw new file mode 100644 index 0000000000000000000000000000000000000000..485703d949e07b915c7420db59a9d2734d2a97ea GIT binary patch literal 143828 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 ybKTY5Y60kLv6RpF~>aP9IV$()d5hpwp@V literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/cross.raw b/codec2/branches/0.7/raw/cross.raw new file mode 100644 index 0000000000000000000000000000000000000000..1b2af6a90fa8da2e83b0f1b5088cbc5ab1dd7f7f GIT binary patch literal 48000 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 C_j8c| literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/cross_melp2400.raw b/codec2/branches/0.7/raw/cross_melp2400.raw new file mode 100644 index 0000000000000000000000000000000000000000..439012cac70fc33d4c7b5051d3d70c03f6966227 GIT binary patch literal 48000 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%0DLpuf;{o^9`2KMvS`&~BQ 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/f2400.raw b/codec2/branches/0.7/raw/f2400.raw new file mode 100644 index 0000000000000000000000000000000000000000..5f4427f2fbe6ce2a0fdf45914db03ddb4bff6ade GIT binary patch literal 27680 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/forig.raw b/codec2/branches/0.7/raw/forig.raw new file mode 100644 index 0000000000000000000000000000000000000000..4ba294d7884ed2d02581931f2e7f021c40f6382a GIT binary patch literal 25224 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/forig_ambe2000.raw b/codec2/branches/0.7/raw/forig_ambe2000.raw new file mode 100644 index 0000000000000000000000000000000000000000..911435792a536a11dd66a208219a30aff8a53761 GIT binary patch literal 32000 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�qlgI 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

q@ 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/forig_gsm13k.raw b/codec2/branches/0.7/raw/forig_gsm13k.raw new file mode 100644 index 0000000000000000000000000000000000000000..71cbe6f6deb8fa4e5db7e8841b30072b1f810444 GIT binary patch literal 25280 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/forig_speex_8k.raw b/codec2/branches/0.7/raw/forig_speex_8k.raw new file mode 100644 index 0000000000000000000000000000000000000000..e95302ef59780c9014be252d83037d843606f4e0 GIT binary patch literal 25280 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 Hb!7hs@+hNg literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/g3plx.raw b/codec2/branches/0.7/raw/g3plx.raw new file mode 100644 index 0000000000000000000000000000000000000000..9970c3fbf7ee351b13e080b3380588126a369fbd GIT binary patch literal 91286 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

I$tCbbd<#fmCzAcp1o(;? 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts.raw b/codec2/branches/0.7/raw/hts.raw new file mode 100644 index 0000000000000000000000000000000000000000..79f869add19cd8f02ca94bf9446cec409918cd80 GIT binary patch literal 384000 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

jZGp53eHFIk26l8< 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

cxB|4k_BX`01 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
g}G`Xb_Mh|?WM(XS7GX@Dn>;?pr`@p)F7LR4HG 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 z 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 N(Zk|-S{JSE{{iAW&MN=_ literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts1.raw b/codec2/branches/0.7/raw/hts1.raw new file mode 100644 index 0000000000000000000000000000000000000000..3369387e09427b08af1be0b29a5077f4251c0788 GIT binary patch literal 96000 zcmYIw2Y3|4`~Pgcl1>UW^d=%G9YH}rKm-I)ktR|^M3i0xsnP^Qigf86q$vtg1?jy= zF9{?hAtCK@ZEtsH{+~DZ`#yj6xv;l4JM+HpynWsokMM|~FoaJO;;uksi42j6Pd2VB zkz0Iah;&>z_|;SVJx}D}J`b(Z#bbPOg%_6xJy0932%tB!xL5j1y(>&%LU244_+|BQ#?WzMoz=^RHWkjQ}msI&r{r|;w}de6%<36hj+qb()WVm%ZocNV9LY) zxyA4iJmKF6FCRuESZG9Q>BEQM4C3R#hcNQs3KT<5Z_-=T8$pv>{0@zlhv$SXQ7W@| zq-;Qzi|^q#vWlq|{+m5l9zjFYBT5k6gkbn5ifLqmN;EeF zB~gvz&Ma=3-`Vgdn;3eO6SY2YbQn)r^m>?tmSF#{OTH^P+qB7P%U((DmO5L`qT!h>d#IE?s= zXh(2(ai=jiF5*Uo5tc+z;s)wH3zSR67>_}<6!AdZ!RJ9S4e9vnJ7dOML1I{`c6_9p1Uw+G-o7zq&El$!i8p!#tL%*NeRsi%@B=7QcD=p zbLx#?A?YC4=#8)(5p8lYI`K|e>l6S&H;ZABEDCe!#6|t(7UPrDCt=-7G$(Eg>vNi|ur3N~bfQyO$A;VU;*n**p)nZ{h+-JR z+(uNOxeDM7n!_;sG;_h?k;ACHW1##aaKz$dV+xUAQPY8CJN7B2*4Piac zF{XymX%Fe=gMj<|`x;n5242E%N} zvji50PXdd@6^YS|;!(o9oB@~!%3I=^xFF7p%lKRe#3VUnF~|aD09pehkz^3uWI;%$ z66ad@OE!UQ0a4M7zdHUWFNL&ISZat@h>FBz3VxM~d62LRYcG;1qSt-Ujm9P(qc>=V zNt=+?2~&nRgW3|rH}N+NX)byuovQ)ANMIWa?j~N>!DqyC|Dzc3W+D0x&jif|aVYU9 zJtf&DeIDl99DMtqjFSc-+0@Y|!B2XFC_>Uk@=fhX8_?X7t)_V-DIz?GTExFZ$*?^P zOKezXNzW0KL^JYPh_A!6B8^YfA*zvN7-&gai!2LiExlNJgT-_uO_&C{5ga6$BthYE zX%rfrs77?Vk53Aok%lFDDd>^7m*k!>r%{PR|93}nN7$2^j55Y05{ zcY=@n0pd`G_S851MwWnNn#Lta>CG^H1aFvv1b^6jCD{*SLROrx4NEm?K=LNSI)}y~ z*>z*S!&XcKe8hR=jS~Of0f&%WglT911JXEAptk`?2@~RB(%{6=G=pK!f#^h1?7{at zXchQBYLe!^j}KX2($ZEjjwbrZDVDmhJ;()Iq}@D#lc+$rQ|~kfB%Aa*y-#}2iFSks z@hj2S1?UXCM?U8r$l^8py@PM*7?b>bf|VpGOdZl@VLygEF(01OY!O8b+&#s84xZ9` zq`z~EX_8q?5t;+ygaEvNc+imI3Gsg;gmoxEMN}dk5(`g320r9}rxn8!_It?Y5!3`X zjZa<+(eg3qPLgmJQhKMDmUl5$8ldNBlZv+#VC@4`d-Hi)Ev7uzD@O0p}Y zqbQQ0HUts<8U?60dZ5`O%S5A+j!iFal>=UsU6u5n)4KVBOLPZp^=DRXfBD?6STBx<9f0c=AgjY#vW~0{dzCe3HK6|^!C^$lba4zA=b$A9v)LID$?CJ2 z7`KDC!^?}7qP}<&oLe5F9%Om={KSs18LS)I2TqzVwu-r8EP9wJ#))r0i*)e@o5WhN zWI$Sn9TvX=rrBbiSR&5iw`A6dbzoE3Sk?lgH(_g8Pw+^ZmAK6|T%o=yb>=ZvNprpNoqxD@q4$C> z6i5$Mv~TcZQa`Pwv#fi&d%Y{lS;yhi#w&j@iFYy+Lc>BmLNASFq08oEyFmOYRgss; zOO!Th1$C6-kQ*|a*W|WUWZpDiwQgDxZ;079nL{2dkCW%fZRJPOY$-;{6W91=K7v=~ z6Y>8BUK!X<=1q+Sp0fV8WXbu8dq~tT?tShLVn@UVTs5T)W;cINPl{)E{*r9#MY+7l zqPSqTSfi%t=OW$lvl0ggdnJ4Pv#4i9FYbFMguam@-Jys*@vkMvREQ|`NnGiOit;>O*SzjIm-AK5sk|eF z2Lmsy@%*~{lY2(YUojnGCPuAwF4oE^bL^i2mpmu)^YhDkV~x~MX**u(pf+<bJxdO?1VS@vLalu^wXZ%i=GhkmxJv8(cG?IV4LwnZDE{w2+jX3B;D0rSW zG`qXHChon+Yf(=k^%$1Cq+E^26UK|82cBPE_RZ;?*7d>j6gjtd@SgRBI>x;<`g&PU zm8c5y66eKayDrO?*cR;dvVGR@ob`DTo_c|np(oZ0?WdSSaVKMoVw_P2Tz#DXD&s;0 zMe7Pa&ikrhg0FP2zp>YDBQMu<*9cdkzEXQzzpsv!j))k$PN;k6kI*(_voYBG!}^uq zlILnYwU9PNKdV+!N2@)gf9(187a>>vtgJ1874BZ{*ogJfkKIiZrKv`9wnMEbuNIs6SNs#c+5Xoy?7Q5>62%{OKdZfU#lDDd z+u1`lLh`Yic>WfD%ImOo(k{7;(m`1(zmS?sTUjIaNSqK=*?RGlHNbdcMB4MjN76NA zvZJcIy0f-=jw$?Sdx)KHw}W=sW#2YSg(euk2bTnWMm?*DFJP(^D>Y%gp`mQaR3f!| zS{MC$y_4QaJFEO6_mMxAQ>A!mg6L;2HrIz*gyc}VQ8VQuXTV9j`bh>T|VW+HGyCmZbfv{;aH%Zixi`w)L4g*ZkW&V18tdgjP8iO1A#8 z&j?AXfa?r2?j!LlX6328SqaFyq%G_>p^6I7^1q47(5&l4ck!t>BwDaP*kGxw{9HOF z`h~uMvp7-mE4uo*bGiFX=MmKsMfOnXh%#DkFYjc7Lv?)zyjA?q1BJ%o(C&~hyI3d9 zmG&a`q5Qu3MBne&r|;HW+F-4|ql(k%_*%QBER=Q%i?`z4?ILT4)z54kDrM{nW*e$y z+v(yTSWS~3=bc4=c2qhgS5pl6rL+iELWj+1$hxw!Y^89BBfJ`P{XAAhx(~g%P^!ho zTPOV){+ptS_N$VowRU~!=&d!73;9`TjAkjV6koP{!O|G+ng;%vNRSeNzx8hn*9m;G*=7)UsRCR!NPqfnwaUn zErBA|OzWdW>c^co^@dstIe{%zWc`M+OkOHAxBB__`8o#H27|^vqjRuLu$J-ESYyeO zqO?+`sav$|+TU7B{j~nVk>flD%8pXrkS2-KVmKQsYVyW*M_8jFcvm-j+XB3Kmb-;z zr`Vf#x?u9h%64!;3+W%Wj#ZMnOHPTildyv$z!6Ku3N{Ls<&+p^Nr7blX**R(P*$tD z^K(agy|J1sjgW_FN5Fe^l{oP**xfG$1_g5ruQ4FFA<#Y;XLL3@i;L1Ad4UpCKhs8O zhqXNIhTh6q%ehcLuP%aZ>x$U$mS`y6mq1v#79nG882>VCyyi5GfYjY3yz8kxV z**ypN(pd&;D189Ank#)SWx^LZ4c}!jyU2VZ(XJgV@QpO9%Rk6Z<&kdzL2HUQbpxAc{BeZ zGz1h>gP$7BL+^*&pq9LPngCoi&)Wt zw}TI`+3sc~nO5iwpDWF`|21FQeeCHXhd(s@_9t>KTP{^o>Z?D=Z%ad@Gw{V?MM=>_ zD#`2k|IJ;N-^5OLJdUmz`_wf&>XW2-iDhGY>fhPJ0#gINV1uG<*}ta8KjRrmg@XfU zLtinWJ&L@N)S}#r(ybHk#J(Om&e>NPYozDr=CsR+%pK+#9z1Ve7Ik&YZA9OWy&Czm zbE>1Bww?WAO8%;zU7oVu_TKUSz2GVtwPlUWf*sqxc8q_LW%}N8V6Ct0$&=8fLA^8kIl9_i?bS zd6aKc54h9ZQBKt{&M{RxA=Vpve3yME1HT3S4!mPmbiCtC@Rq!HZV{PXyVm3GrtG54>u;f2@LxN@_q_ba#4-AUaYb3JaTYpvyfQ77YO zVJrK4DS_3p&sm?le5EUwdl`FAzG)c27j|ms-Mk|&KF^P^&N@%Hj;pS?fbv0=NAm&6aG4QrR&q;%9aFv%44GNcUB;TMw_jC+TgwZOrGdSB|gy;*EcM zpN@O9#>>S=&nKr%v|Go2SMBXe9ivRsrPnC=b>u&Cw0BKfxtCo+5ppZJitQde8$Y_I3BV<9at+BgzQ3jP_WVExT{ z$lbIoS4S--bNu-ZsgtUnY+Jj=he<>1mCo9Y{z%-JuAltn!s%!03nczy`dd#c=|{_b zU;UkOon8M~fHGUblOPWbRzY6CnfN{#s|T1!8?9OaJ!u(tRja^u-tfOYm zX9WpGe+6q;<%-67nu^v5&e*&9pAns%vC*GI_q3lBtqI1P|M+VL_7@EG>|<$a2W_GB zhuqUS*s)HZ$KMMy3uXm(8b60_*(PtN+*Du73SGGVd~aP(n*j-~_}=cf6N63t4)ez3 zvuo2k`(t0aQ>WajU6@%N?%#M_^G2W6Cd-oYvx|9bpd z>kavKLZ5OMl8VeS`IU_l`Z%7K{d@Lw&mZh7_e1kb{}#D^^n;kz+FSg0Yb*bTcMFvE zM;ra@v(lo#j(fwdbP|tRCD&adO-??XT(Wjd?blvpo|~2aS?J{RO*h}Tb}dDXT~h56 zdrh!R!kg9Kcy)48J!?QwWXuZp=b8B_Yf}pHW@vrYul&`_6^ZXvvdi6wst{5YJ$e`K zn}6Wtk^IH}zwNiYSMqBxmn#+V&_Q*zW3@Y9S>ZqE@6YR*e+I7=st-RQ0Fnq*~Xs-ADuwI$|8R*H?U_j&aVtQEx`q)1UJL@XLb6#QbVcS6r=}va{To8U=Y>W9zlK(%?Y-C9!vMesgq; zSoUAX!;h~Ge!4zG%^UU1_KYs~XL8x-#H6P+u2$btJ~6(BT}B+_ZJ(XHKjV2uPV?M5 zMfa@xx>fS6(oJG7C3s3ziR+=fY5#352vqls&HN@y_a^&Bd$$F-^nJwP$j{s_9g|!; zT`skxXylufe*M2KPpg+`nz;MLvKW7hE_GJCGBzkX#jMc3FZ!^kfoDtFf@kmMDc(}P`POEoPt>Q0XQQr1 zJx!<h~{G)zdKt+*+^8Jj9D1PwApHZX=v!R z;Ck=1f{zN{_H--yDUf2F6}9ErdP!FgXQVc=sOi%s{L{+*z?t;OTElBsbk-JFmbmD(#J>g*}QaZ&&YxqMrWS zR-C+>U6xz8%jssp`x#GNUscd^zR8Pj_(Ad#F}iYtq)*~{L?3;=#2Zw5KKk(bXzxw` z(no*g%rku9yaS2_@tcaMVw1v;)HsAAnkT=bn9BPxFTKLjlWnB&}u?n;i&OWm3 z_$0Dw#6Z249MDpv_Qvgi5gHwO=xr37Y`3z<*w^?gN&~ZJX6>TdrJJ(K52}`_{Cdqm z-4ab-Ssl|a;kfXGuDBw+Paj@=`K6MYdf}nZ{K=!ge524d=BjTY#_H-yDZ3@%dp*9) z_Og}TpK5&~8o6#62LoOsFK86)dujSdhCBu9eI7B2&9YPE`OXhq$&PDk$a&SFvswHm zixl4nn;QS}jphfzxt7Kj@z9Jw**CN)CAOxw^EPkjj!rKssooisk5%rw* zqkXEVUZy`-$EtKMB{SRnCa)-cgJ+XADs;%6?`jpXDE>+0uBd~FRT8zx_UeGRca$Qt1SPi+na*GYMYV(?6J@=Y< zp|PTrC}AJ9YqFBou^z;GnGB9)YR; zz3DA7>K3N6b1zaeSGrzzBwCtzBeq3iC#iJA#@MTIhobJNe?D_Af%ki#EY*F&atS>1>@ZnRPx)@M4h6Q|`#(s%Mgcz}!93ad5Z!4%dOQCCG- zlg_h4yo2vx{=52vk`oF$=R8f`S0>(E97>BBR;Cs&XS8=bKGZI2~oOh3~QigD@&DELo1DG>};TQV4lAq zSjM#duh?H$W9*Ys9d=iWM6TtmJWn{(A&9NEiUo*#4QmsRktVSm*siByBikvj5LNi! zQj)w=p2MmkntF#X3ViQx?kLjx`Yzbp9S+BOwUgMddDJm-bH^UB*4oD3V(sl&MWc;c z_OjrK;P9Yjm*9%1sodhV#|-sLQyP|t6SS#e zDI%3kZ`wQIyKOwRk4Q$?r+G*bw<9+bCMd zUmz=}@;CYW{GM6P`op?mF1PpE$L#6+thg)Lh$AXVYn3y|@$8dE$}{Cw%Dd7f_7OXR ztnPNiOi%e`B(tM=e`Gq}6!j4wtw-E>9&xl!G-3xu8&Ol#MP{~|h(sPVMYKT%;5X5Q zy~oC}0?~>kO4)1>yMVl0U1Z=li5B8#?*?W5~CUV{akfd!EG$8TsEii23%51U3yhWf$AT z`m%<2nkDY@N@B67Bu4WnKAgt_v;N4pH$om`7VF14Bj4MNonbXW|F-M^n<3U9$1qh? z2aGMm`=SH;89CqHVh`^mirBZ(9YjkjL|bWy>_HxCkJyD->W>WcIM#*zz<%eiB7@u> znb_<6s5Q&#E@sKc#5?>q_PzY25`*~jb6J#SA)>!2 zp4fldKJf)B#ryO6pjU6igMMqOIK$41p1}JRUO^rq*J2B#Xhhfpa>TP)g&zFy=+rZODcvr~Rbzs`gsA&4^#(YKSiXi~aU3&p?=w0MRa-q~u zepAj@tE$=3Qt63YNlg`T;wEduR){NB9I`lrfKdf|B45w5?8;&kuZR5nR`AppqN=<> zIxOCmR!cw1L3WwVln*0II2<|sC88D2=Fec0{<43w*Yo9eJ?P)cqBL`XGUp|)R6(97 z#mn22Wc357G+U2|H(gw}2Ky62^&qK34R2_zUfuN)YZ;fF7b7jDjkvB}QdRM*kq{bh zeIKmmOZ6rP`-N5oP6a=<8%kr@Za!A6?d+=GRBJgh-FF=>?I+#VgK8z|K8u$A<)^Jb zLSxO}&81P$WX?c$l)I7@95=Y)`iZv$K!ORpt*d2@< zdx17XIVN;%fa|orL@rd4^mO*bT4D{bDuoXD>iBB}lY;mCB?DuvB727QJHINo)2b;? z)po8N=P*YX$4ZySxlR-6S88wNRkp!?V1HjmZVheIhPI<4iQeG|lrMq%3wYoA)vXuqu zZfJ};SdX}FUA155$IPDQ*VY?YC?9BbwBP2Bc?+?Cb(2TRd*qACo9Yv#nleCnUuhx5 zvA4t)WVAhe38cQgsH>cVvMb!(v2I+PKZZe$yQ;0MNWv$5^A zD+w=)luIfPlucSsy`w%5S*X&EkF^Wx46H^(NF`Z!vBjQlRkdcBwar_h^5!*Dwm!1z z+b#KGejoN`J^P2ff$Y);@++7fzw}Z%A?M3ur2fz_Go;?gKXzxAkq>Ia-?l4aK6~0F z>4x;WTvr*cOqRctyD2xNv*H?783Wck)(QK#n8|zEN2Oih!G`jE z^|sm&+3!!})#$T)pdm*$nw8gw{jx%4g7TZ;LHE4!kSph3z0Vz&-BF~k} zDsL*U$<3tGQXjcFtjTetB zos-(iKS~-TbsX$jTd|yfXIHg1+X-SPGRZTfmr8f&Zv!ho`<0pUPjV_d!pqsh{K1Sh z+6S8%HH`>kr%}Ud3;SJ`d8N0MCrT6Ki*M`y>Dl`Gjvw@Fb%?q^IUzj|&$z-XSvNx~ zk-^(<>^D|~J~GdnhpqCwD^_vuvC8rdSy6^4hH^uxsGOBIVjXWDs|V})geUT{(Ekzq zx&0kD?FN4r_L3?(X2a@sm2R_Kc1+4bc5#%{P`bw?tcq-ce#sQ2`3XB-MA(}`|3JbQ z@(;x`HcUOPbykn+^_{!*XbIuQe|;->`!n14sP72mT9=H-5$1W+!-+1yZImPTQd! z*IMbx`crj;vRoc24Tr5!?GjcKQ-=nqZN6^iJdW6_BJXFtQ*O@{lvm(^E;X})a|0Xv*L)Xz z3;lhKiuO);^`GmFoo_pOIDM{HT>G?HN&|VSxMYY`8}&10@by@!Y0Td;p5}}yIHFW? z4d;3C!GzdS4HNc8?Zry?QT=7m&g_(#Q_%j!y=SYkdU;A({g|rXbO#cKly{e`9LM9X z#x8P1ncV~Tis}{qnBO_)!#tPYw4T_hqK11?%&3^-QNf7sBDy&zDZ{W%T{V#I?Ns<{ z!EWz9L$cl%edT(3Q}?w99??HyZ^ZY`Ve&=3G4x%arO)pfS+o?n%j;G)ub@2FN4ti( z>N?{cmSRhL*)u!I91RI>XEZSWGk>!}fpfkM%Fcv9tkeA{c6MT!gu@X7dAYy<-}gm@ znJpjhN-L3@SNNs3zcE`~9W$}i%#uHpXqT9hD59^+yNsRw98c4NMK7=B9P>O5&11*p zD$aW`(@Wfl%Z!@jYNeaf59a4ZjS9*aHY`*`FA0pTFJdQ`!js7CGN91)^obuE-S9l_COkQ$UY({*}gMx{Hx%NwCo--}FPg1qS z1F^Bu4I_H!clh(*grbs#Zx+?_e(1X#>?)>e`<+uGK8buUvVG(nS0%LM5 zBDJdOkIF%%CVSt0#{1a=Lb2vFK1%w94U=X4P-x)`y`ZA@RfNNFPCMjEOXyd2Pl=nX zeefNz!LC!#FymVKpD3cc?>pwXQq)o^jM^JpJNkKax%gWNr{e}X&)GSl0&`Wcr{{S7 zd!B`XhgKr0SDwl)SI@}h?i|NqZI4m{t0_(F=l)T~)zB9IpTXz$WmLQTE;UeIuoStC zT2IWkgW`Mk#O`iS;5V%oc2BG@?h})w^6GM>7FI|fvoX>!X%&~v)@BUTtOw;P|aFZp8ljgf(i!4#|-KMLJ6&q_JUe^QQY zs$TVNojI;4HI+TeD#U}SVlgts9T6>7=gsUX_CkJ*U*yrE7d-osh!0Mp%4IF9fC__w zsE48Yv%{$5Nx=$TFRa_fB8toB&v_A_i8mePFpll~$ z^DOAI1VojeiV3J&s*mcLTCi9h0p+h)xnIb>hp*ZZ6ugQRQveas3GG4}@!dB8wmt#>_Q*xHD%PNU5Mw4H^>F9TjlC#NZt(Wn=YoKVUFL93ohO72}eqCwLVruw?*m zGDf|CN}dU*_cCLA_~u2V>W7G?0B@e1`lI3Dsm=?QRu6eKn#aB zE~8y*^fwRv{lvzAc2%)zT!4zHgT*wviTBQ8)IwlF7&K(f;4M`~#S&G#-v*ZRLFWmm zdHNM2|A83Hi~6YAXw{t6#T%uuR-S|^I~_ClzZznyaShj;1yC=iqjHRDSzX1|ym1(v z>dX}8MSI$ra0@VA2ffaKrWeE|TqnUFr$OD@c>WlzsJ@G8Y*Uai;HcRu3!Iw*^H!L< z`hcZ0>Z$_h>l)s@j2`c!wIRylc?{ZC1bq@PB2|3TZ&xw5C-J#}JA#rbHL04}h1OJK zOzl!Yk@KL?9>kW%(2goG4N#~&e5b0I-}vG>J_GOGMYY)jjC>6+W}rHa>L;n%nX0m> zs+6i9sX~=%DXA{~I(nuGLksg#8qiTyZh8EV=4eILc#qKIb-+jU%$Lxbsz#|+G7@+s z;~k{9aWTvx?VF&w#s5|MWdd%h(WH9H@a~3GjCdbab$8JV)f`hjHdQxM%`w7f^b@WQ zCU~hYs;;D3X6lt{MKz2T3vNgToCIOGYMb^@gzMU=LN^^x!&Tl?RT{3xr8?MDz)yAA zRGm$@+{FxKV`PqgsK%Kps>9W!BtcZ6O*QkxId?F6VeyO*51v9@-XT7TRZ?a7n4Kt% z71cs{qMQ7Zw`K?UF3XV1YqyZ`kmQhDPVS9tOXE=0(0u7|XbIn<^|I!$ed>qEg?;0I z56dH|!q5EIJi;pQ>e3`-iDii;GF3%)7VoiB;+mAge70A*!QPh6v8&bsMDr?dDb2K} z!PD(xcVj1D7w@oB{4U=i%>rc_OF76PH<$YI-^3L5fG?LGBA2&VJZ4nan8{j;1MC#L zYX8RCL7IEAiT2m*EHZqvkTGOXrhCUv{4Nk_ttA`JmL^ZiI|dNl{z4#c^b9da(my88S|vLds90%BKnYRg{z% z;EfUk`88zO5R0(EEQ=3f+n^h=Bm)}f6w@RRKg;J!?Vx>Pq^{6S|MDng8XwxnP`WfYJpa3WHL*QC2*sZ>#}CG9{2SckQe8t~uk-r%)7d$jlo86>A7%d_g-m ze?~pz0P7dlOdbFn%F1zU2V}c}J)ZB9zh@o!3wB>>#ooj^U1gpjI->ly8XqF1Nv%QC zi`=p;)Hl_K&0Hf5mQ2(_RFO_dZRBbEHTygtg&gm6`@Hozdd}g~#Um+C@hH=kShXc) zVW`Nks#u!Uz_3^hkVwvIOvkCBP`9_xTZc^N6lh9EC8 zN?IY_K=jGDkFUlI-nE;d7VR_XHF*K@aQT?eBxFkWLt~RJ@j}n`WIAG-(;`t`0R9;O zTY3`Ky07`nY=nB18CYNF%8$xBGy{@S+gv9lN`KkY#TcnAvYe}=8EiTKn?2<1`4Xk2 zwi-EqU2@1CWb1m`@7w>`4-g%9K-^oI_pvXCAREfZ@O9EWWsqDCTH}cPgY=zv$^T&i z`MhNC-uxp}pG+06gZ{%`R>c5iy!PZ>u zi-;xaj!-YNHlG)|^3mSDz`Cvu&sgtAM&RwS^H}cYC;r@|SsX6-!QFv7;S#GIqkSFu4 zsriX~QzEaeHhW)QrtXyrLXU&r+1(N2=Y{TvZi@=8J(2a)wf=rtJ<=bWKbAPJRkrVx zI9AnJmB$|w-vlpOn~Ya8TRmBu^HX3;;Hh_R@UC3wz7ere+bK_Uba8*CA3|;ON$XEr zLB?qjn<357t~h3*&S{pCEX}f;SUs$|p}wIT$ig8{kBt70nDZ&pW~`jtPzK66)<}v_ z!#F5Z(k!qWvfW}T8>FS^uWGw^>s0y505SOOb0wQ)wkTP$aj92Z#O`=r@9t~fe7)PF z=o1Grc;sBYSz$Y~d2CMUi)AOcC1a^xHetH*XWp@bZJ|i>N1kWLSkv|F=wIFIwAB#- z_wUH#SCwUJwWpKs&)|k&3Eoqx%`PkBoNKi>tSK}S4Xs@BtkvF*LSB78e`rmEcWm3M zq(kZz`BPRV=gh_ZPZqrr+vX+z(08O>_a?h5yl+&!m7g+IoXzu|=z9LoVC972s@LBt zYEGp&HUBQN#ctv6>HI~1klQxxLhk55AA7%2RvGBXkDpWWVdNgQzwVXJ1P^+b7JgBv zhtk;z>lN|HJu`BZ3=soS&8Zt0C>GBVF5%OwtuCh14>OOSE)flrI~1 z^Oj_0W^Tz@kUzk8mX~){i~b?De%yn&W07~%@8ywp1@GUUSG?m2?iU^nma`7=+3HYm zZ*s&@WD}|=&852hdEo1!?+X9RKY$8oPu?tfc7>gl|BL^wOubi{RGjPh!T%f;-TytV zackG@f6``o%7mt{w3u!cqAPt;rc7do*vXEd`Dx*w*$1;@bHB}duV}FyaQqQDDSAWP zka#nur0b3Xofyi-igKlbP~idZlfVh{5nD*H0)_s!GKgm86n= zBHOC7&7$0;Pv3uXCPhw*c~RQ)lReQH7bhh-O6@G!Cca-}9c?t<7IB zI5a>URT7<*A|fJpMf7#Ia|*SKRF4ld8yJ@Y9Rm*om5f^E`}S|*6}boOVr}J=QbNyH z%V7O0L8+pQ6E{$&rm?^AhR2%E5As_)3Kru>R6{p}q_;sFT!lZeZkj!V9|RtoYvrHS zDe@8L#kdBsQ{CI0dz_nL4LWD^|Ade zA0*nrGfcty&_!6>wo+@XE!k`uc6gLQkJnIdnk<&sJ+L#Ov6#j!cyM3ALz@AcTos=0 zG{j*W*+{INyRarK*gSCoHMR8+ZBOINIcMD@iWz>8{8)e6gjLj)VjZ843~q0%e5NCU zu7q`~RKz4(;aS#3T+@!-$NE4IK=H2h5qz`rtQS1`%dnoR_!p6JDMY`334q zFCoLf0xOyYh=uDQf=%T|`E_pa#;8xOh&?S=S&Y;eeF=D7-HtY?3{Hw1KDN=m;oA^q6gsV5!iZ>$4t%2yR6Rw7cf0E&k81VWZAnv=22!P_A zbi^dIzbUTRS4l#g6y8yF1`*kP(5NP|1|1NS_d-8zmWp-Z8Da=B?!DmK9!K;-vHNH6 zoZ6v(g;5MiIfJYCpZ1~MLPT-~d5-gld2-?7md6gBMp*ZK1NN#iV*LAnccSP4e0l)4 zZLoZ0u&S{bYrQwIX1o-m#$z>eC8F$h;vLWq{u$^U3vAl5ui)qR#sB32S0h^6*No&rD`CuuLQ3z36U1<)TUT36TecN z_7t&T8E})kI6^PP6N*#Ado5XUoa;nX_XsrOfU6PqFO|X5NywDc!5pgCm(Y{dLG|$x zjC%(wu2G=KoA_-SUF9UYbDv=fnHO~UF#aSMvcZ{zs`{KD}>2Zm*kHJ}JM9`fS@zvh51DelcgZziGy z4bRIU4ySBT3Vyqd>lAje9S8Mj?>oWh#C*|d7C}VDdNGub@C)teO9h{wK-=r+kM{nV z$XC?HTvtV}0`H&>0=SbLq{0Js;+c*}JRYAYNCIU~!lz(RET0C>D-<^uy5#G5^yM1XtFl9Vw?>JG6_HJHA4|JvqQR)^TBRa|$fw+>g z8nmyKXmJM_1Im0{E1pS`mGHSJG#2etrz{1vqdlo~o zo&fDnroE8Vj&@PfE@e8=f%eXaPt2h)X|E>r6+VN8_Ns>Wn%)I&#B0-k}lyN6V5Yalc#%yBC`1j!;#97p;fV)~~Q- zvIrj4S1IR;n(2d_`$7fUdgeC%cHUHzLw~dJd|haY;;<9^7qxHX6Gnf%gZS3`*3k{Q zydUNJ<_c+m9B-Gzn&cL{NZF^Ju$yvQ9wBY8RQr&vS?{QW+1%hpb)a-raDAzn&p*(g z@g%8)bjQ5JS}DCyDYi!h?50XJ-o=_D|7K??tK=MGy_(I++V!<8YmK#0zGojnR{4y1 zQ0gQ_iP}msdOxYv2DR2obIcgjee5(3iNnmW$|)12BWAROtQRnAXGS2t-C)hrzPEm| zyXlq8)>3=v&(LP|fcV6|!{+g7uu%P_bUP?+N}Sj;OKPiA?qTvXc!L zv!oBjDybj*gVJ&@*vH4HD4HR?h5Gq-LGK=NGk6CZk?MSi>a(#}HLfhCBY*TevKw5i z;x({7ki{2(D}F`3XBzS{i@@*ypo;A}@?0CG$>1GL`kbFZ%-Rex`5CI6mSJ__K6Y$v zWouynZm<#152Fy5HHCFr0e(vYKK+2zZp5M)&|t$E=!3SqQG@jrxNs`+wL6g8iib8j zjkSP7;QLFkS&zW)uNK#vy$U^36FMLVR^>i=yavuC{gZ}Tt-1J)ouc6U^Wf~akT>%} z9%7JBy9?c13zG02dL((-0lSAvIsCpGa+n1@qGKOc3|f>1CN-g@j$^j&L)KjEIG`aN z5d(-V=!P6fPda3a^at5!I(JA$WUWC5q~R?O;JOMcavvCkPiztRPN)3bgv64y2=5&y z4d;b-P>7zBAP*IbwVH_@HS|WA@)y+P9rstYs8fze4mvCq|Hlq!UMcuzy4?+IQ{)1qHN1Hd+&OsD3K8BM$&K z>2T7E*NY*zgtrNM8KXzSy5@lgXt!WCW{6fG$bQg?A7$VV#e?~JQw(t&aAl!%xK5Bz&Lb%0$CNU*z+KZ z8U!xx;%|g0tqRa72BcL<_mdw(r|Brg-UGc)xYFKw(yX*=pIT|4MkJu8GX=;NWde?? z(2TS$aR+dQeFxh8uYqEbzzb=^;(p2Qq@q9ColiUG$$O!*EW$R0^5%3x1N}~RhO8B3 z{d0;TiUk%<^hD=tq~RUPWz#HkU`XdPB!HUaQ;=2W_?>#9RTr}5#9`rckLbJ$I!B1? z37tzo>joM4TnF@LfCG6Fk1#6vGPJ&siJs|<60(Nj(<8#`1?1To7@25Ewt-H=A~@-6 z2C{YJx6p|LWO?cQ6}ltKPu7-J00>jEpTw19g}i{G0C&WzL=Ez3h-2tn4?69D&X1r| zk%$jzMTvNc{8y4Rvc_rnOLU|2cfuzch5eE6$xC7DN|ubMj0oV=9^X+1qr5D3YK1Kmxr4<+Qdyb0(@O2M>j^xpu1y7vE zZ-h6sG$F+l%~eJJ#+JDM7=IhV#?^uLbfQZ5XRIXtftIH+${OgnY^abFKY2*tD`l7 zpW^Gqa%8)wAS2KWm7Ech4>a9}*t$MeP)CdX+-)y2k^{}m&GL4wfxcJ&OKa#D81Yx+ zeWy=8!P}Xyp~7ak|4iZh{4Wa6de;Wa*^@CFNu{@QTqUbkbTO=F76$Kxv3tuiaW5{g`@A?#~tr71lb@z8ZRHSVmoQt@WK% z!a8L)VJD>{@|%i^U9NuRnle}Z2vwi~thqX{w(}`s@HdegyzA-o@|j<9+;Ojtd=e#` ziy|u}9!y*jF;={74Do0MAA0uXK1~1NS%VihAut8n&(FCTIYlqW6@{?VcdOAu+}2A)eiZv}?8As39RKO}v?WR%DcQQ`ujbq4Tjc-2 zKi=Ol(8EaJ7v)82cbrR*uLtx$^(gI`lm&_w*c(ytUkUYIJ?+}^3d!)*$e5b3i0v=^ zX_@(@-iUkMIX5xBLa9>UC^ZV=vj0wh<;AZrW1fw=H~GQ$FV6WpEAL1D8dV{Ba;an0 z7uQ@}{#3$m`Y(28UY$?#t;qZ-jXz(U)7-z^dTKp3-&gKO7bNU2IXq!oWRku@-Ku`i zUbkZX-u&nJ2}MKwt^F1K-GZLbF*Zg2$n~-7SLX)jD&4L9t&C!I>;$u=xzns}HL!cz zyLbudta3(~YQ33vDf5KwP0TCNIIeQc8pU?}7IQd$WW-2m= z##E2#AE#uyt~-`Eue&-Vx=S97`!4no4(6#KcTifYheEvq<$Y;5Q(>&}iv7%t#opMq zY$5hpFF>BCCRX16mcLatDJNNmJ<=R(mgEV1u|3n?W3NNiYE|hcsU+&y@1eqBHqHz& zQAwdb)1n_GOAdAu|MZJ>hj-#M*j`#L>bbXsFuEjwV}_YS@>H{S^%wZ6Y1(|BF%KE4hga}U;t{(#=co&)5`cA%p4BI-5& z!)F%WUkuNIY6^}+&x{bCVQrVR$OQ2PYCPy_0f|ZmHM(N8ZXMS7PeYTtp) z2jx0Rf8b<>{!(e_C2*+>{glqT@k+cF@55)}TF#H~lF)=+tX9^=xIZDYR1P~68cWG| z<1#e;KxAz)pwHJpKVOG_tqRB*AwyNI*vH7lFH@17Y6Gg5Ld{HhRHe6p&bR=}@+vgy zP|$t{+XC&{4|=#FyqgT@^bw#%8_edXXt^IYT?dVav)zam3ZPdHz)~#68gW_d_2`03 zPPC|p_1mVRJ*eP@4S9)^2414oPsng}f`y-t`F@J|NXIHwHvbP1LV0M{gRp(%o>7VLHmY)vchtHUL zgUW+phZdr?W-d7PJB-&C_O1!w%Ru`>n76sm-g9vM4D8k+xA!yb&${Bfb$GG^Sf56p zR1rcxb**B{-3Ix-=D?yUGD4MLPZJ=4RDVGpw--J`5}uTSHKdG|0{T6I9Y0i@CHn*T zYy&4L8Eryj;h6cOnE5suqpF%2J*J1_za}=pwWK3eIFQ?#OQAT?)s3EN*LY5 z(__GK1*B&&Xgd>BUIL7d6}LB$pKOj%`h!O&U|z?;@A(+xQ68N9U#c;=49Je)ItBir zOw3(e;cVIY|D)t?(BvR!couv`kqzZd5&&@>K+z05g`G&4=Z1Jv9v?b~gU;N#3oOFt z>5&&t-aq9p_W)L+@qWN~2%7Q|Jk3goIMTuCX9b-y;lw&=J9b;lMKqg=vy~p8GN3Ig z0eV1FRYr_Ai`~I2%!2%^Ms-^&>`B^*$oLk#r>`Mng`h+kag@IT9Z(a}or)^!CB@Zy zZ2-e9@OstaSgR4n_zRM_5!wCasCO?yU!#CaSMcje(Hi=%HnhBepZx*WQzB4d{w_af zKQcAz9Lthpxx;p=hxI(AgnUk(ueMVL$itXyZLlW^SXI=YGv1lEF{3S~eU$ITER{t) z$~@&W?O*J8D1|)+UG+lcq3n=@qC79eZi#c)1-QY`L!VjG`E{Jc&<>U7XXRlyc;te* zKucAx%geBTPLu11SgV@vLP7b^$MX4r!*@bm6?x6|k$&CrZd6X>5AG4lgU~HhQBL#D z&i$~UgRg19w3o9zy?v)cIiNQ7;JMnyz8}5Py(Mm1e7WeZ?itR2W1Lb_7@-aRl)yw^ ze8DB8=zj7)@MRh6QAu(@`AU0+y}}P%o1Hhb9{PE0Ez7eT+XZG{<58d#&N{gplC3oJ zO;jPRm;1^s)%}jEdV8gm{afKtPY3t(hz&2U1U*#>V^7$1^=eVSBaO+r7^@ z=hJzUf@_$&ji;0Uv2-)C z$@~WO?X`S=NZSK#^RFzD&${QkUtmP^IqiZSr!&Fz~T_q=>|yYxp-wx>mMIz|d- zl`)t5S1GsLbE0}Be339DdS1T0vERgf9lcXM+`k9h5(Lo+Kmy@0wpF3W+ z%~fU->80GoGsZR5-6F>0x$pKyf99Sqk5>CDim_V%*GvoD3Vs)96{#HVtsh2~{)(Nb zlt%AMoO`Y7qV=0qMLrQ8Y~+u%wS2)3;*S^ED^+sW&p$ExZ5f>y+Hk#d?*72r8G6=| zj1H+AGUf(qh0kW4GX8d(r~|I!D;c-KAM}>V*C6hL=%rC({dfFlwW7*m=Oc7?9L${= zJQkXso10xYP*5Kda)rBDeeI7?_w<3fNZaoI%IEdCz195VJgBGE`e=jf4e0QyW@Ln7 z!=odELN9_}>6MLE<_csSM=A@|p2}(aCuhEzsy23)bmdb&jqzem$6vk$QO(_3p~EuN zVUbXvUF4Hsxt#Yi{>_~iSf0H%xHw$bdK>d{PN+X<|G2+%-}eQg_xtwyS4VA#TIL-L zZkevGa&DsI_d8=G^0!xzcfAoj8H&|^M6be1^MpMee%&1PkUOFr){c71yIX6IwH2e_l1DcHT<9 zG4h+vQ&fU{7^!c3;_T6j=avtzF>8e8209r3Swk_E?5b2({?2|&9_cFPYO0oU&-4E5 z{u;A^s(D6hE0sQK3uUn5hvj+3T4anezQpvqh(61BWKJ}n8Uw8#?eCCRmeA)^2vOTX zsLCm*yg+|#15}b7k^Y26`UIKGHL#}A;eC%qXeHg=iQHogWI=~xf>&qgi(lkA&^}r6 z+n8}ROwI@It^#H@Rh7}tj*i0Bb_=VYSsuNc{jFTHCu;B-p}%S?;#!EJV**i2`3-p) zI-s)P#omN{`!?zkPeJk*M||%FG}ByINS{MPG=dFQ6F+l$)KuutozTRk@+_IA@RyrF z@4W#_;V|^%aA=cQc-FC~hc1V1&6&_jx1n8!BDQc>DvRuJE6fqh_f&WQA?WZO z&>yVFEQe=xhsJ9Fdt^PdjN8evSHKte4Y}-t_A|Q+Y{BW!bIg_`<>|NlfYAWxmtLrN z-V1#*9=huozQ)5&8VjAnYDh*Tx+6c>30ge?8gUzJvu?;SMkB5fjWs+tT|e0E%b`0D zBO1ZkrtHM^!JeoL8*&UX<=^1-UEZ9|H6g2xhoXoWr?YuzlWuRreWoza0BN zjEeg0@DuvNN6AE#Ydbij2dIo$)$aJqCA^N{J^k_5<5;l~;v3QU%7JHD1v!GY@Or1< z%ww_Ea$w*TPF@ZtpNELgY4}Gk@Zu9lPo%64SY1>G9E2si3NRUqPtU|_K45S-&%R@Q z`wl#f(Wmk7PA1`9i*T9)_&q&_7@VOAa?{gcU9AIFSA$N*z`pY%?!O%zz80qsA;T~R z`~L?pyaGJ5f;D~sPiq3tOT+F>P-|(>Qd7j>x&T67W3_EqKN*&9ZCJaL@zlMj8@Pe5 zz4&=H{D#)BCCh;BneAhgkrCH(pt)aRHT?um+7IjTCZL}T_|w1U@7KcDCVb`rQ_I2W zr(xeQ3s4o<90YpY0{YkjpKmR2Fb=%MGkRU1B0zQn7z5quYg}m7XsBZui)A3U31#^Mp1$g#${Eq%Jt3H@% z7MXQ18CU^*V#p{cl{F&e@G67<=l}mtv>{i;tr4W)bi6oMnYk(YtDI-en<;MM>1VLx z!+EP809R6W(062?0{taY0BczogQr&;5BVOCmDx$bti8xGGY7!x4b}lMZ@^3xvsT0f z^J&abv3i9y7Mv*0Zjy6Y`!;^d6biUBVY>n0GX=l82r;LWvU`&9S1on}zmxFL;K84vT&Y<$#*lO;vmP-4~Mpn>%Y3ItC(^YNbo@6LWe%DQF znNrXyY9E)f0*2nx8K>M)%bS17+q6>X_8qEqP}f-x)#p|yJVb7&KeW!-ikV+-VEm|d zmR1?vJYMN1%|;B?^895K)c%zA2Jd(e8;8+LdMz@_m91ApTx)>d)6>aZ>)e)pH%GW< zIqT(EWwdQz>S!U<+_hJ(qdN6N=e&_C=h%!~yy*;fJ#q%v$diI=-myQCW$O!NgS^a~ ztjfj#<(ASbT*)IjW97EmlaQhfK@2oOD;FLH%722&x%aHsv<=PxO_Q$}$CMX(4W)=0 zv`lq{zRyWeb#sXPpN+mk;Iy4Q);JFjxP&|$eXc$2T<3|BZX%eesNSD<_*r<(iXdcQ8iFveMc5U73WK?ltuWWNy%`Bi&Q;JF~6-%*mMF@|(QhE@Up08o~eG zhZzW0QN#WlYQ=Y=v!t;cC6BgOSp85zep^0ZJuoLY*OZe=N4pKC7_3nXs|BqsW?Mv) zvrv!R5SU(uPK`d+DXSE^S2iN&pJMlL#waCSUa5xpxwS#A?0Q4)Xl9uCVRw~#p`W8OW;QHB9sm2%NKhfV_U%vL-!sF##F=4Z zKAiNkx<}~*>GvVJRJ_VXREP|+wxUZWVkaWPo8oj<#>j@f#U2T5)=*x7DTXu6m7u+J zX*~KWuSq?T9e9rF&~;8}^OQAOJM8L@zWt5h={sssb(^)uWZd$sIRSk@&-6o*mK57F6@V=Zt>*xwl6%Ri`J%L&dV`-$2{ zDT(b1b%vTx2nIh(5`$u_`blGkReYy{GFVdtJz~j40 z8|`PgD`LTJ%n4TH5mL7OkJFG-B$PCHD*B5aTc^=u(b7Hx%`gcaI1j8?WVPnlC+$V3 zvY9C7D3#=$*1yOu)s{D@NtlhZ$zE%I5Lu;9cO$<9m$!G_hgVthuFJ_FsK%A?N^RrdW>88r) z&~RCIGD~Lqt>*q!@#%5z#EkV<_xq=i|%Lf@+Bvgt@D4gZs@t)cVzm$byaDxh<$FM7hq_69h>DT^)_Lo^ zd_hg{H1HHri^1MqqrTJWk*9y%+mJmn|4)_5zSgD8;Cw|qW28Tfff+>~ z_qku^(Yo}bkwNNm_aygu&urCJ&Z2YZvGcB3Ou7c^^-EBAU-hKyca8N%JnK9Il`Xc{ zC>7ZkX&7o0b{U#l&;QijN8JsZ=6!hyawYRoQN0myuUhD>_}DCAUy)STZ7p4W6SI$p z+7ZmsfUoYHmp(+4u$ufbW%A|H_k8((X;HChtr`>atq(2E_&lR|#=prQCcbw!;qiar z9lmWvIu^VdSKHMvxY${yTu}Q-E~B2jB@(Mt_m6cq^kvC+JW1N`w&JqPq4vJ8mYWk^ z9K5W(pmg;PR^y|ld0I+!&8^u{p<$tuMk4ZJ7o3?!Yx}lb#n$05w@@2uFQo)60rOox zcKRZ^cU#KzydCAYVsD>1)$Yl*N*{Fjtoia9tNqKK4Z2)My9o+(k({`L8L_Q&S??!{^-cs=-5%1dQu?91rFMZWbIzSpdBk&~W>;nq%cc9GQH zkgOiqd0a_{(Izc=n5%VGDymGA{*tFD8S+VagYC6zW7cII%+~l;*a zpGHl7o_zbGq+`!tJ_{z*y8UzV@?cLiH~z12%__5Fhi5NIK?7%YVt8%lsMKz$7jrgv zzbQ7MQp+;u<3Cpp<~9sG43!Qq4k&54Y58(1%PkYO7CKvSa@28YsNo8I5S*N|HBdOx zBv2&0-AVLJi2E|%qxeUzbNY`#BX9tdwx=5!yy_3shUzDBFDb)0<77cgc)OU~3r zdu-PUb*)|9Ig80HXSHvg&XM-P+QHOR{nm_!{@4pG?sq)Wphm_0@}j%NE|$7GHTBT5 ztmJ<8%#?4HSygVdTGcSIgksXyraj4;ntdf_LTr1dtBB0m%RO4Id&8CZ|lDEFJ>&gv}Oi>2rM%e=AL>` zDygP^xaKb%ZoRd)#=`in&;Pzy;(F54rm6i>`ad}O_*(Aw1vWP7-R$gZRimO_q$C|p zo|f^35yYi7cT)e0tc&%Re^j$&g<}cdgibyyo4PM!RIp=ik<2@p6$9lxjSBB6HMCg6 zD8Jn{>z(vDSv9gR<<7}@5a{C!kJ?qRY>|}(6<;tsIjeBiq<|5c9Jy_VoOap-&vo}e zwKb~#7=aq2B&y@2X^7>QHCE``(-QAazkgcYR6psR{7p+&iMT&`@X_TBccPx3NY$QQ zeQ^6(#Ynj#AJ(7oW|s=ZJrmQ4KlwK0Mee=Gq`>C16{*uB6QlZ+s#U2?sikqVjFs6x z1tn+CVGZzg|esL zczAtI?*A%OX?wQm#@Fh^w0hYSm%0pnne}qy)4LBJJT8%w>_1X|Rn^qugT0$W53{ES z7a3vu$4Fexi>&X%om_EoCW`CE`J2e^>qqoOMo)c8ctPM+u&vQSEsrXg)4suKb^C-~ zH1dU>rLWfehTXxV;WkQ}c&A8K!5N;1p~G1pWhVtrgm>xP(TALdC(&{*Gw}PDjnq4jT^zHIlYW_%CCMozEQN>i|jS5vS`Gc z^M`7N62fCmLmln;%fHICU0PyC!-H9fdf5EN2k0aU+8=p3x@W7W+(SG&w8`kxd=MEL zxe$3j5;D3=N7Oc2L{_EJ$h|$17b@%`9f4}oUooSv5IT%|JC9-a4RTlTjdYyU`^kG> z3{VG`7*y$tQY905DhZLX!Tg~63z?ZOFTO04IVZA1ZR>00+paBz2j5*;q1moBF2B;w zZfPE}df~2u&gxENz((WFit~yk|11S@_s2xDIK0$4&JjdYQ|$`U_n4b8PTJ`-v>#pqlN|Vu!@%`dygkR!Qz{7m1{VYlIVX z1A&fawzCg2=XuB2ROg_&#g$*%s2qkZddIqKzd#gs0&L+Lh-@dIs%5S`!D(z=vEH@6 zvgRS~@+RgiqV@$Izydo9J-PX%TDU96kUv2`K|fRsB_QIFfQsTdxTAuTzuLeX-VL7^ zSy%MvFLy@BbDh5EvM%kEP_m?PN(!b`6?QVrQ}PIT8Y(_UVF$k=8X70{HT~$JI_nIQ zb;N;uxR>Aq#O>d5YRC%m3hV47O#4K&zdaUxRz2YL2An1GDr6NpJ6~A8BkOn^lj_e{ zJ>=t3hFw=3gqoR6azWgs(?yE6la#kGyX|Y~s+lY!#*BInkJTR&O=n|P<6-n}H3PI4 zNE^^OJ_OPFwbCkU9_+}^q=CwFqZ;C>@0lN|jnN0XN~sQix`4FW{#p*$59MF%la?X} zZBt2gZdu<+SFBT*p4wY3BlodJViIF4y1|Y+53Lksk2J$Np)5lebz$jWbGP!EJw@IH z8|R6dq>qsX$)(LSZKAnE9VwMHj(Yk;nyYK2g5lo2??Ww=j;;m4-#o2M1G>*JI=J&2 z&0WWxZu$eS6}gSueH^2;y2~i8rAbGvY06rC5HcH0?Ypjz&CAvX?Sk=?S)3FR@lf^1|nY5T-~GhQAZiorTVU;`az|TwG>`nEvujFeAw@@q~`is z-fX-b%LR7bz)kowOWG1SC1PtoTXE7iN*HzOEu7LyAtOyrm#&-RT;a$Z^pl^7Ty&SxJE~sgP-ML) zF<4%?ru-V|=^GKQq+C*KM0UB|`bs51-4r?N8ie~vRM^DL)ie5a_nT%5yQ+6Z?g-2h zY;Rn5r9^VzQPsDLXbp_ZT5suqZh4lNXPq7D^Y8>E5fc)Z$X_D!u*<9}^;LB1J>^&X zC@_B5+T~=)A^n(Z0X&6caw$E^SIK%YANr$>{~^NC&@|i|18Kh9&hX%%Xip%*JXNC6|>_id=JXRGrt+`x0oTx)N}gb4?pduQoKy}Rnd)Qz9jrbaEfB_=el(qh0% z9Wkxrx_rz0MedASvkECsjYQDWPOH1Bm@6>d_dm0l_JuRiYNXz@I->);IOO0n^bH(A z9Of!wzzwC(5gQu5aHVKghC$@(-9+bQkfcqR4Ai#+(TsymH)&1_}BQQMtbmmwO%YxFx7I z+KB28H##gvA$D9Ak=q!=Ag3Y{ydSZ=rHBqzLF99GUUai4BE^hoPDjj+bzN1V6+(!j zu13#i7&TEgBDZ%S)5_s}3ZnVD5Usj|cqwmIs|=}_4A1ca-p5`i6ZI~sh%hpC&CWa4 zYqOfB45F*7Dq;<^3w|`a+1R5f{(l$m<_)Y~tjDe&(T&B(J-d*26CSIj*%M|WvdSLK zaNcKa#2NW+Mojsn8+f{c`6|pMUcwnzg~RG`)_t>|fc4qDtCG`cxF1G<1K1VwB7^`V zp5iV>AI=&=)>7O9Df$su8_zDQ`-s}lKs<;G^u|Mx7 zV3PzYU=JU=REY&~cPVewWhFdsGJJ~9Ie2#}zVo@9GQ_%mc49HVNNlk0gHd4agSZ!~ zgC4OeE7RHe!n?NFfyPgH5f4|8a}>R6tk!>qy|enC{cI2LE_M|ZzQ3;S@jWM^Fv+cRyuEog1O~(Y5BdDV4hvzLq z25!Clx*CTt`9-Ieb<_M0v9tHFyLO1Kv_W>O8uI*eQKed5-ixUVM=%G|wC~yHPytX= z$~8CZqpXGU@0cg+)A~x+&}Ti|UIraH6S<6$&i^nYJ_{S%z8g7G_Tp?q z9&I@wI0m(I7cuGQFIY>Zq-}WjD*Ovse$<1s#h%-u!`y`|(hy9W4uRjxf*MWGv=0^* zGyM`y^*8Fi+Cu6L02S=OZ0?TebSejG9}S#b#L9I*zq_%UOQ<6K7<*$bryQ`;98U-# z8^tcCOu%drPSqT=zssPDc9shociVO!kir`ZhK*_wNG7~FI2gdgR{%3G{K94<@%p9^SlDGMW z@FZs7{g57|P=9w9{6mSUfO}Z&n2GnX?v)(D-XL~EvD1=0NzC1d+ml^@9J7wepbqA* z96X0l$;K0s^44PyS28|LiOO@vKzb$v3haO8#4~1u(tt%JFXP2KZ$%eV44%h+uG^5w z_wfmK$#DH#&}j^07w`Ohg!MweOBl~NjTP9p62TKF#Zv%B&Jbgd?QxtS0dj`@vXoI0 zPVI(09|ulg&uu);%nqqsoL=;!aT-`^-oKc~Y&Hi zHFXrLCfOJEPhKXOH*B->h8?c#kPYFSCiYw$D;mI?3b^ND*D3f6=cuv6m2>JSd86~5 z77u7sF7ZZKb~Ukzla$FGz-*kncpmQAF~z^0#$SaDeE?XcfTPL)<0|OvI^NGIeawJg z1MDtgRaUgHJL@TUDjL%kh-aRbuw+J>^|{2sGn_L79=(L82k?8|SZrh3gMu4M%K{6R zfDu3FfVBc?paTQ%F>sovSa~;SuQEoPC7r{>@!QY&bHy)pV9i5ZRmmUR-tHUNZfu2GY>(v84s;JpH4Y*9j6s&pZjVy-U zu>b2iPT32U7~5dinDFrYIOPgFxixC2S74WE!0d;smSVQ#QdQ{$xbvm!LkSEY8ybk?bDm zBI2`|!*7cd9e^~Q;7kQS_rnSmP>bTlJ6WaE5|G@Khmj_r%zco4zarxjDqpD^+Wak9r+vfqQt1!oHmh%Xf*VmZO(HJ?8;#fZ&6hx`<7P9VZVMFY2#-lEz zI@ZG4fORUejIV>PzsFpzE|3<*VPUMm^SUAHzE!TPM8l_Ffyn=N_6*o1Rpg+u7xF8? z=?HIY4JuA9Av1p;{>K4Gx_oj6#3W{--YnA@j2Rru(Bm){e)3S{4Avsb@IG!yn1wu1 zU#YznW%(g3TvBIDbcO|kK80dZvQ$zoB<0u>><-vtA7`~4u-f7@cTibJNgao(4&2-+ zyD^2RKc=T)0yLz%4J@`r-3@Kaj&hp(wVVX(N1=mZGM+n4zJ}Wcy~sh8K;;^&W5wBo+zQGZ4ciB9)5@cf{TMHO%pbkiI*3`}`R zGWHm)jmbs{vxYUm`BMH#t&N*9d%3dIj>=-(dGfPW$?9eO4cj1qE^ACb1K+WV>p2=;R`C7(+j49c#1xkj`M^;8I=r3^FBr2}7=l*eVPQD%m z<|piq>E)Rvh4e3jZ6Sy!2V)|Q^wq}yjG4x9BVc@LzbT*AZg?w2jf`#|HO;$KoA2y3 zmSUcNZ0KR=Or*cD$Q*>3ZWpbS_Ht>2`o6oJ?~;FqKgV0$HCMW8R1Q}Q-VJmJeHGD- zafo46K|j+~xr-8qI}w+=-gdWg=XbqSFxk&M8J?eeGkZ$z$<3#)9^RpR=BI6vHg=W$deL1Bt9ztFZp`MjfooT%5-`e zCByYXOM`!f;v=IXE%btz_LZU+G^3H}UhAskD;9M(>NEd!k4Ky3R5MFQz6%Wu8KH@h z9eR|RANSHOw);4nq!r2@EuUwTx3e$kt>@W;J8Q34cl0jd3ZeMWf1w?b6~-y+AE%$3 zq8wA-)mCf$wKuiRpy@VB1KEX0R7tBE?!<|Wd>d*I?xGL27OIzgr(?77P0!ylp;q(- zZI1O$pmWBbFGr=0NL!QHHdhPx*Joh%;Cu3~+7i#gC|}&Hgsgl;6UxQb_pMZpnRP>3 za-L?TWwip1hDTbNsn%j=g%p$rs~5Bip8t7g`qujV-l49Q@=7ZM6QbVdp%&5JMMdxots*j|b(Qg$)c4$MZ8XyFM`r537*(w|G3l=$X5DvJ zJF6FzZpv}Q_O?NDbaF1(b&zHCVv656%=_<#iYpa-ztJ3RRtEO}R&4iDe@e{w*t^kf zeN)vb*2UnatlAl7+V2^MvYQ8c>MaowE{zFE<6O7gH@z?XZ$y`fsT$qG-^TN&vf3V^ z*A5*C^b6pQ%J3<@o%O&Tj()TZd8JYU)9u!1(XR2Xr`irRgc$(_ZX*naJBEjae~)}; zd}r-PWN@eQk-832Wrg|`YEL@izR+<>C;757(0&7$$TdcrxNO?Wu)l&P>4XZ?$*7>{ zi_GvF%Fn0(*oZTZc81#1t+$YWpKX1Bi0fk1hMq>HK|M&RjgZ3AA)5*zeq6;dvlQKAh2<@}f&}XsKoMhxT+8QMxr4}RR5s;qCBNR**#4W@IWV%mY3j4Sb z`aV9l%iFCnU9*y%571d}Z9u-hj#A&%!ZXBI&i|)(rhAT(ZcT~Q55(qF%08MsG|(Wt z$#@NODbK+#dflB5w^_dC{n^{vyT|jo`=FXG{bp^~2ZfbTIQSs6H`2yjXdgkh?r1ej z4dZ@}U(}&Eo20f!G~7fiZ=+e%D5obydg{xJrdAy%R{m5OtX@`sR_m)PQ1$Qu?jRZh z+qSoJ9J4C=Sdx{DUe2JEZ5M#o=2ey{2b7hFhA)t1c@k`-+322ZjXMthv)qW`>_+Uo z7jCWj8R9PH{J}R->#z`Z!fe#l)%D_sHPtPme1%lQE}A{R!s-oKGjz_1YFlp>#DN)9&#ROpiu)i zGj%q);;xE9)^K~9lZiVfdMF!l&OdN}`!J=9vIPC2NvQi+hw75P$jLuMKJKBdpx^ln z?xks=)KfzEX(_6fZ@_arfa;@0nBCC~n(2G1E^aUipvwL&d6B$RUW3UZP2@0Q>b+sR zsm=&{ENp?*_9@s@^Q8AtvGEox*$(J18UPsliRzb+&>dxJ?lIB0J;oeGfRoEn$D>Yaa%`A z<%pEvyu|H3XHlut3wLM8c5m#cG~SmfrO3Z4HPlM#Y-PQ?9Ttjd@5YU~Um*K1ANBup z(7*U0?9?l`0p}%NKLhXm;K@z~HN1(5v`tYj|HKAVVTnA*tI%nJd2X@DxV#4{JAj$o zlku)-^s1+#G6s_zVbKpo|7Hkzii@b3?T2biPUtuXo8@y<;?}}*$HP8}L;dnB)Y7hp zP4*3-(-MC3aM0Rnc>6!Wdg%w-csAmbJ76;&gw2IpsesdEayjXe{i*doOri1Me8=Gx zgkj5V#vGMp^3O^^M5xQ7f@z!ez)~@nx3t#D)x`CM`o3J)%d9AuTTKC>=ZMQ}fH5p=h{urr;ya&^$?*T@W&K^Hsym&brn3~Dd_!wpIrti^4} zaok3%|<1tr2q;w5pC&;c+2Fx+T_}hk|(gP=-vGS{~rb_+z+3*B4Q!$p~Aik zY_Kl)3}+OS$%~e(!!swNGM4?G>|#8a=RJuTY)ugpWW{_OIw>k*($NC=O3S5b${bWf z#41g3pIkO{W&&oRCgY}W{VlUzb9dOPV z%5uo*)3{A-IDDy2@Rz27Qm*5^t|7QNuDvuJ9m9vL>FD47&%TBke8^?t49}4hS*Z+E z3MqeKE)i<}FA~3%Yy(=

jZGp53eHFIk26l8< zx>4|D!pNDi2O=8vVWXTTs7t)&d?wwntE1y^vwZ=T?+5L6aw}xv%Am$D0sdr9#MzUa zQFbk?^~64lNx)xY67qigF6Jg~vuY^Qos-rC^&3k;_T-9@DV0!cV}kOQblLK%Q|xz8 zemKxR2x)T&cV4Z)w1|#*(c6!u`QWbVn2e44=HUxWbzZ`Yy>DN~TEkI!*&j6VA$*{x z@GFbMyWHwjlg9$zhj3R)b#&NwuxCp)ZWU8xMLLGQuGi4Tcvt34=5cZ?CNKUay=G(j zqcq!Utn770SXY!JaN{q?95zDD-*v0HQ&*jVEM9wMx3${I#64A)?ea>%>HvxPy_JIe z!ngLj$^<(e+}g-mj!u#b)@Y?PxZ`J~5q!ZCN{V^i!JSu_j(tU1XIY@@uaM!ah@PXh zcCf^oVz3=h)>v2IGaNG>s-0k4z^i&O?Xc6)?4*?g zcV1NfG|`cuJTg~FQaGVqjTHdPE~nq5yhU?0S^r*ZHZCrdT(b9)&REm6C;6EhvA zN|()8wW1VjbyU7}&LA)O0ChAY)UwV_Yqa{g)yOHOUNqz6qRQ{qCHOQm?0(XHvz#5C|hau2CDIzcw!Ebz{O!D5nM8Eu`GI?DUZKa?qQ12Y5*?Yi|N z&Nma2zSn}LKE+h+=E%p?u)aqZR0lIgz2JOjDO%86<7BCynib@H$`Z4!^e$jt)|sZR zFut`9YwPtjxc$7EeqV)cWDa&UwqDq4)Y-;I@@nZ%qrP^@xobR88#-uTk2r5uufG5m@qS26Fa$gddpwSTR3b~SeseXVmwb?Y^>Ym%vd zId_5ka5YHsb@ih*DbrS~-E->-Wl2XNtLBUEsWCP1e@hmCQw2T|C3(?xruo z?CX`0!>$8Paif^~nDK*MQM+y2Q4ULO%xBsvbco$|HMT1_@!BK3nDecgXstz!;1=sc z^r8en=^dm2_6FyKGR11)>{K3tt^(-GS|U$Hb>1a;qM0UtCmH5nT5bCnrvK^~;qa|; z((Iu`aO?d^B@uPGpDPdSi&iUnF(gMrbu%gp8n`A|Go5qlbYv23d7g0-RQJ%Tjc0se zeWfil?>f8HEWJN0yf*rBZIl&ft#h5X(m*pW&6cPDe#iDI=!>??NUz&z4rWzb*MOD% zW>w6!K5v}X>PsihbhQTVf4ic7Y#PonwUaqQc`8rQzfiVFhpjcrzgBPOC#4}OGQW|E zArclV|76d?jrV_8Rbhiq!sPiidVNii-Z1C7YMOp&mD0v6k9(8`z?#jr;^nWbOiUO* zXT77AF(xUxJisWSK0uF)j@jG=ac}h_?XKQY`CU04x#oIc4YEh6iIEDfmAK!vy7yxE zSLa9VL1c()E^d3i?Z%`xV~P74bG$LkGYVD7^VIJ8Na=5-oc$bCy`^zuKzI9!{GsGV zEx-&&mF4J4dF1TEP0CYoH%SY1gL%|xrkz7S;u7_^eo-l@Jl5k7OSq}m($33L)1y>2G7F(nNBZue*yY%OWk5 zQqFa=o;%n4+iau78251#juPDA`c3W;zUS?OYW(w_{`N84*SrMwnMeEFX=itaM5^gb zK(7By`x>&OEpVsJAD*g_1@?M(>&SEIoL0d2A37X2TAQ>GZcWTmcj%3j(`rS%HL5%= z>xa||N-Xl*6|~dg4)E1-1HH9WrA;W#m5dtt>+(h=pM~jb$~3bk?n3;_j6(0?R->kL z7Ip3moZD_ayx)oSjte2u=Pnnnp@dyaL%o#AuC!oj^&i*3aB0o0T@HP(EK}!1K38gJ zC&L}&dD^l_EmTC0Frwl8thYvL!8zy84kIa;;9>#>AXv`^ZjrsNKoY7WkbR9HD1g{5D;TGnxr`W62hxTprn7UZHX`V%t zteid9IWEUZjV;{vDRWB0a%8dNou#k{2H3Ik9aIh_D!4nj-+OG0SwcO}_woUBg5H*U;J%`UxE-q3?S*j+Xv*6FZ{;$h8} zk^95qvk`xAJ87`h4%z>}TD@#{g12DW7ad(142$+WV#mMRi(xmtw5wstOj%fEZg~y- zhK=xB4M_NspjGxRJ%b&^JlG(_>Tkn$x`8M(=Z2g?EPpC~w-x^?g_y00$oC%DwZJJR zNhe{3;wpS!hKYzzF*Tca;S@m3^lQZX)1XmW!ULQQIW`!P`4h1GlMubGjfnjZuoR2J zI^6|c;cZR%v5&RLE_A@IW+UQFyRjUweHtg_RF~b@-CM{do(q4Pl<0 z^UOphEfqUqM-^)d;$ZW$&x{#)&U$0kj(wwHoPphHFR(VV=Bao#r}o{2XTW~3(|{Le zxiLpp02vT}p6|lUIVU%BehugEF~iLaAZP2cbB+CE%*tQDd6>&$XBm6G*gI@ujR^7= z(Rn$p7<}jcnClTUYSXYMPPYwVx16cW%7JXG!MlL&<7AomEwgv5Ea09ACkfQX-E%%R zyY$WgU!3elxN%OiiKj7V$SMtH)>tbbUd&u^9u6xOQt(bbiyeE+gRyQQ4S(f4LPCZe zY^*WhmN{I$SX03lv!Sd}-~>o!<3t?@*Wn3RXTaVlhh+>Q&=Cv9z`Ec#j~+Hk+@?=Cn=9PUgo$t*;(wLJ0uP{x$yy{0Pm3E`S@>6 z)FvFV^G?DpSXR|AZ_X8&JEyeZgm2!^lb&ClpIpPg zk{$)-`AqJL+(kU6;`yxa;Ve!ubg{%1DDan02J!^H? z@5+p?lJ^pD;uL5%xP`R|oE^?drQ|CyN0WHx>}T>fdtr$$@)DSq%LI_Z5 zkx~gWQNbYkPl;1@_loJcW8ciN zi<7bQmNik74V203J?4~C6|jl`>!dVRKk!7HS1x*f#RPoTMzAi45V((>usc}PA5ls? zz&hk$Y9B(A^W6DP?o7}*ca)k3c|xBufc#4dOe&!ihkm4qxgqLF=4CPX6aacg}C;i#$LsWJLv6;uoLzim#sL?O0Tdv96A|B|JFg zm)+9bDJRJC9sEwNBi|7tJj;VTY>`{UtX#?*@-+FGu#5+Vu-ll`A=C|&E4($2l8!K7 zH6W+Ya_8xI9@j|5i6}KW|6WXFCDaK=ax>w;K59X=}sdZ<`cPJeu=Jf@(ibh@$Lmy=?Sb+qEORP zs*#&WYlIA`i92I;3h~1G`A7$p^P)#xtizf7gbw8|wLGEDee?93@k>iV=xySVwhggI zNKl4Qwo{vO@05b9!V$d8J#e-eVMU3<|I-!{RfE*Qv;zol(k*+q#H_DPVN`f%x6$CQ#X-vi79dg|4Pe;)J0iNi9-AnpX6eG zQ95uUKW_=3-XIkcRzjw~z%I^#!>M(I1}F7%ZPIl#Y&A}~qea8oBvLqOl+urUNA1dg zacAUeRw@$1#3C_B-OT5apM>-kdY7;!t#Cy_0fZOj5G(#($xBLS>O*3hRGW@n*}xSi z7Pzn$f9BK!+F5)Ou}2vj0<jOV*&q0IsxDxlf)-=zdZsd6cWt4!VwiQQmP4K85EZ z-YIjan@F9k+hwgLVa#{&z7)cNRtRZ{v_R_T$tWX9rKAShKzH(f;{GZ1_-^ux&?0;e z;lYX3d^Rel zfjuF2D96Y#!VaS*C2vvdkdI$+0yPWm2HJjv6eXvyy!f3}Zmj#GW)V{=sLwcQgA$)y zNjsPn&NB#EB>0uy0i}RgwY5jOSXyt7dIaW)e5 z7-{qd{w1iB_9kVvkVQhK@n?ZON-FXJYaPi8gb+O;p|vSJxIgMF(l4om)-P#*a3pWj z9^qsUo}F5syA-xJB_S zj-WQ~h*0J;iIZ3MGOaRlMm8`@4JU4b&4xClE~h4D&AqVi>FH3~5{In1C(Uz83GJB6 z*d_l)-W0f_9;DReoOVhUYFVyEz7RGd?Ka9vzAp}6!lR@ON-03yLv2M&@?HErpGloh zn7pz`X^qkk5;BJzPwdeaq-Lis78WzDJVJ-CB$jyQR}z;rP3=ee<}?{vwe;gDhp0Wd zHt|Qy@VzKWgVLrJ{2{Ce zq4T&)aw?xsjY?`0b7Z`rb@BkYm{v0BoG)S95(30OeK_IQQ9BA7n%YZ9U|J;9wfsMK zOT2O>%zZ$B{wAdg;ZCejn{$0^1Z&d5CT^%5DeWnZi4k^e2+M}J6BZzGC+JYfDB+XP zbENl9DARkQ6-^58<>?f9!`%BTN)Q~vvr!TXzN9pwhr#+|?poZAL>N+25ySjEB?x7< zpmLs-oI*TO7E$?>3;kBqb8!+%qKx zr5QaW0Rcjld*bc{ACU**u%p6w@g4(C9U~S=Ny2ub)S(6=kI-%q{vBlsYcnNz4G;h9YIMhJa|HdKA@1# zqy_p>oGC@Wl$=Aj3;9Eg3j2>o zpuNRfdt!=K2PHNACPIolCeA^97Y}X6*-gCniX2DnN}VfYp0IV|auJB>)ctDg<8=jc7$^IJhj^GnvZSk+9 zW_rhj4ObJE9r=v3$kjz0M)-Nus*GCDb`vs!Qkc@7mKLEZGzue$?7N~|;Ew3+3fU>F zHQ`$eYUlI0H{PvAOj6eheN5Wp`qUzX0<9GC9KAVGq>vBfZ_)-e9(6h806#-(fqHMAIJH(Zd%*>AunlQK!U^u&d4PF=xsQyNhViGDXqb81)KlSb+l z(I%dcl7+Snd6`s7h*91UKI}-L)TG4a--UkU(PzZrVL|Zu#GHr|P(!f;hPx)@NKfPg?ofD2{7&o;7W|p=O5lXrKs-rE9-e?_ z;%O+ONGDJ8;7aYt-%uL~OO8B4pOTzHXg|Y>!V42piu@&HwXm&)9Op!KVve>3?=uq+ z;p)PlCESP`+R~(SN=eEI;+NfU?1`i161V;^UQ4@<(N<~(o{ZEg;svxf8D*vqL|*6l z2_=DD@+E0fV1_#&RnnfP{G=om+J!ohpWqj%U*L`!SWIJkb)%cm;EbhGw@_}9OGLat zK#$NQ^hnFX;v+wC$B*)0Oc^6=cIr^_0kJ477grv2GIJp!X3SQI`;{1bBb5qmMn8?# zENu*Ne;;L;uqViQ^iN)KrSK3)y@J0eC#dPDJ9%D0>y=$D^a~^Llr%ArIfX%=jCWAu z&>j=so`|9eTa0|i=kSgz!jOL>OgJ}@G{#sR<+X@-@T890{-*|2?x>^xs^B| z1q#nnP##Y!JX`LM989>1Sd)^N$4>PteA{J|Zu%ZnXs*YGKxkx(O4DLu(s%uf++Lh4iUzLFYzFD)-2BWW9x zvZ!|mW8$5XOV~~PTzcO5_*}w?a)gvZPl{ARzlPp~h}TgHGpfTEr8@l=T8q4e@s*S! zM{^oIp(=Jxok_cskP(qm-YYx| z{G0F?slf;bQi`xN=?f4Z!UCapDC9HYLX458xqrbc!mbq3h?GG4N!SF`JH)Dx(UkwB zXhGTk_bF;NVvjIp)PTL*)J@z!Ju1=``I9t5%sXh!}Wnz>3PD&BE6t2wk@%cOfEoypaB2&fegovF}$A}z~ zuoc7}_|#YQC?qSb72$I*0!#`Kz8B#{*(uJ-6}cNy2_Yh|#d8SxPpAoqQYMR?k^Y4r zDfTNY1HPXcg6E~DF8EGJX=0qxQp6@Gw|G`zAqy!Y@GPu0@-TNvZ7ZTOq!gk5gf!qP zv|UM`w1L9lSRx$xv+#9=R3g>#9P9z-$+$ZAL2ecLK)^*{mk|N# zs#jmao9DmCCxZS+vBV?SqLnS6DtszRebPR8Nx*@pqs-)I`3XvSK7s2CYlgoUv@JX{ zL9zTRv)h!sl&*vzpG+d=AeeJYiuSaF?VmQV;o(GD$p-&lNdb?vav6*xSOl z;~LbcB0kA;@f<=bQ8LkI6x1PT;1woF&wL5&aeu@raZZf$JEg41q>xs)C!Ro1DtV8R zh!7OMfY85OgMT9p6RIL#N*N|_N)MR6vcR9v-NcfJ-c!%KlEs9h$QV;@atC6Muk0`Z zW6E@{DdZ#djfer!x_U*6)PFoBPfUMJoSP696iE5bFIuyN93ygq{|HxcYSIqn6RDH* zEF_emPN9E!K4D)7Nlwj4>Jt%dau3faphyZPPK7*vPOkU*Y1jh;4 zP90ARI~gxV0+_?0rN9%@ws=LKlsCd!p|?h?5NhNO>R$S%(UA1CD5yudH?G2W5HsWq z;z>{?cR>xolL-08_X^Kiz?YhUJEFBh|3t)OMFyM^T1F*A#D`QvDNBkYjHu1&^9cwE zDMx8b4&^RL@q`zpkH8*tY}_$-M2XLTk$(jD35`shMarYMOzHlA{sW~WX_M4O*}(5S zosdD|DT1CU55!JMvxE;}E2J3zB6y#Yiu#d%BUA+63q8R2CF5hX?1bj$UWIO=)a72u zF|@4+H=&mpTfc-CXMQj~K`BGrkuQY|6WmO$C%p*ImwuwS6*U3>j{}D3;V{ZapP6e+kdzv;aPs?ZuZwh53h#m0kC+EC$Mq(I~Aw4rjM6A&&;cC30v@mMA%Am%* z41Q*8iuRP4S0JJV#E+mup=X&DIGb0ibngHAh=M;TDd<@WJuJKqas>A;^7WMUf5CMDP;rJnoJXk@zMxQ)Ur|uU?ePLPn7f zX*2SCT$>*AtCNbmOvxeC#e60uhR{o#gF^_?Bc}b&%;hzFk*=75U~GkPJ=%97R>I62 z&m=UEpj^^0j~)T#EAc>hai_ff_W~$@*ryN3DL|~4p{GE9mvUctyQCpf(ASmQk;PjQeaznFe1;) zJ#ckeFM^BdF)%O8_>!mt5k3Id6dIYke&qp>qA308S4qgq@#NHMl(UqFVntSKaUKw7 z%}_Sb+h;zN5e`Cz@`uo)Els`_S#;L15oY`nQjk)J)F3F0G)F1HzljF2G` zjKLCm%x-XZ)HkGBLYa8tvlz2u97ouqwDrh?rKoD=mFu)m7uQ>L2OCGT|*_Sbo#c<(jokUKMQ0_IUL)g3R^lW}cIK;G`d*edCi{w2>q z{lPVO-wCU%DPK9ahFJ#EzOZXW#E>?$@bZ`|rzQ~37P)f9cgW48dr}MYX2cFT*@gYk z9-vHSd`@r~bM?d%ZA4NdaZ8Ot%#z<2eIo2hW299$Cla6~`IJ2lLa3Xjr9#oT#%60bJ zj=^O0VRB9RE@nCv#ypT3=nVcg@1~gXWl{Xrv9>&~j}2jI5|J~0(5S8$HnORV{Nq3~8S zNln0BC6WI62&=jLE~fZ*@u*&px4CzSyQ+E{y&heR7LjJ* z8KD=U3z5Ob7Bky!CMPK)wU(|Qv>WP9^%vYp@W|PWDW}EJ8y|y?|5}*uvjv^FdolB@ zzcj{d8{D52g<$0F=vuMUW8a9|9=|gGjQ9briJ{aCSNf&Yb;6D?JMZ3USv=~ zCAjrk)UBNKGa1KI)1O{=QX(`qf7=ove|z`#_)P_-72FX!&|H)m8=hfT3*N~3IM7uO zXm)J(=px!MPkiic-(y8Ly9GYVSsRJ98ih{<+uA*~zV5!BV%izIkQA-Gkl(P5Vm@*+ zvxs#Pvl}j&>y-hTtiGfEsqRn{)zi`ty?SJb)!5E3Z=z%5XDLC=)>33YChXjoXE=rB z4_!~?J($JQUQz8QPv+n5V>PZEC{-;IG=~tcq z@+T(L2eoD-+)L=?@jFqW>iP_Ag487Ier|8=zIVC5neP^64@`}!@B7r+8Cj|?3l0gV z8U4eDB5$AzzQ5f?al88{mvP5sb*Z8AyHe0u8ZI5#VhlC@HS0-x`X_nEV`f zbq!NGs+fmowY7h@tJpoPpY#d32VFP`n5q=3T~Owt+a{z8)XJdiwzIX%$*|g^cRm`O zdv%maS~K*#Us1X^K}$E2^{@51b~oH{c-Hlr`k@o!GNcAMAD|QLq5FGll`$H3rF4~^ z1wYE!Zg@TK#JuUPsGf0$e3M+ojSq5n1!tPYEl;FUq@`5W-5R~HwVfH5sbi{B?FE?4 zvROH455p9bNzw-OeJ!9om+ENwyw{b@HapODOdL6e{`g(8sn)lf+E0`k%1wKbITok( zTet%rH=eAQK6cg6YT46puSEq+<(i0TCs(A8mT1pTZv1t(}c{jpMG%+CZza^#ZddB-{qy-W+bW^YnB3aFcy9 zy1BklUUwAZw%x{;F!UbEd2~;6{zh|q zuKYwPZjH9fC4$6WU_O$cI8T z6}J-(CONyb{Fun3dwRJa8tCuGJ+a>#t^D;oK68Zq+;v*&AHHI&G>1X4{Nbt$7yYtR z7Pt2lFuLg>>6E*+>kITOpH!FQcC;4u*ZN6gtMr??%*ND3_ik;razR@z4c7Nr)ujiK zHlf@4-_kbMYIOoS`L8Pp9uwV!n@Po)xrKSI#XGug26qbJUb(Gg;myoL!80l+iz7cvi{FlBwcTISqWNQmzO;2h2 z1a8TE$2n`iYkgv_mu9(AEiI?BwZu2XYL?qY`U!Vm^s#bqQ)szx(BA0jB>$>UlV)kT znE$xdTo@UnT#ve;-Z!QwgS{J+9(sS{BlAh5Df)$LSQq6FJin?Ft)g-htq~?W$2vu= z)sZdsXt|v8htgUasgIGTM*YwIMR;krfV#vzTX~sVHoKQ+XzT{-YHofjE2>#cf;}+M z&8*^WpmfN(l2c4}ds`@bjiK6Tx2$f^jyhG0%jRq98EwDwnKczNv}d|j*rx* zdH*mE=wGRZ|GvC6@WNOnXGw8JmEbJrzW2Ik2KtQK`Ley^E$7 zl3HNGXKVFq?V1{}id(f^bJTKr1L%?I);9g1Gt$$@GgU6=JixT|H?^+7dvT*1riRSb zL-GXWA|`R~_tx>LddJ+)l}U1v9<8r3S9;5P_Lz;8HJ(x0MY)lEEpp7d=JGoW0uLg0 z(dTx>sO7YTF?Py1NBM%e;|vxmtc@ zu(cmEd@6_5>tj)I(iAi5+R0U2eoqNC2X~gh*0Cfl{lZkVY4j$$gGqZ7WMla2{73D#=kptZrh-QQE*gI>?Sq@i|u^X*U-A%g#;OxC6VobWO^yt+CWSQ2_}Hsn_N=fMNeAGNtTo%>F0j9$ z-4AG^Ra;hFM|^YKx6EgUROsj2p_y4p?-Hwg99hZtMU3eI;*QDu=C zFMZ~1;#;CMwhKQs{|ToSt<$%D5q-IN>NQubjrrcneCPJCTR&&b2}dVICtlY#6fPS7 zms!fSBQ{_BVDHPwt-wAf)&H+`CgY}F)?LTf*1tAtkt2cyV_YhsE99SzH(Q#ocWecZbD_yO!dGQnw_Hj=wY8_uiKeD3D}k?%cU@&iT(N zsml;f2^m6==WO8`IbLT_cZ)r!RY>nWO$L%>Q8T(-mrLHUav-4rghqd78om?oTiSiQRg}??BW|6heyi+yKzp(2@&8M-isXje{7;?ghYDxd8z z*qfYgsz1EJ&PdsL;@SAuiT0JI#P^kM{Sf2IJ&QPLk21WB{xi&6%#YahE6M)UuOVIM zTf20g>|ok!oTXc6JZJc5ZDlQ`u+l)Kulh<%cC{CO7nTTVR3~aS*8U#yIlORZqHcaS zUkY2sJ*ru3E$oCtLr=pfrY=!NO>sO)a(?RSx3GF(++@E)VGZJImaeA%mchL{ks9ZC zo|5$TTIyhOk#)OitGR=9Q)po1BEPeu)zd|;Aun@u%N=g3BMxDI*B{n(F?_Q$vz9O{ zWcyPcl_YtRFT{0A+%8S#x2k7R9XpGxipt!*WEpay{4ZZ$X-7{Y()oeD*2*Miu8yYy zr4xLIy!k)-`Ai{qBfm$k4DA{6w&d+_9UW{t_UpIYfjQ+;dVk-PIm{PDt))Ne##*|B zT@B5*MCmG!kI5JE5YJXyYJLyTWw|5#tzXfH48zPWQw!q}Lx8RrGLZVqqueirPD+A% zyL-AcN2-Vl?KeD*3Xn>2-gkM{bD*Y)7S;-7x@Eykbv(D zZAAU>HF_|1Y5U2fNZkzOfnP@lb=2qPnqu{@02k4lNr*bVOm2E9XF z2v?Z~@Ne3UI^-0*D+s$vEpc!Ns;_h41N9V6M}6^A0;3yg(ucBQwS7*%u`6YI>8dLBUyKe%R`v&3;D%;ICCo_&) z94Wk8vBRj2bJ~sl)^yZ#YgO4AVw?u#K~o~dqn%@bC_RA3&>r;dOV}mf#W!j?)(>d! z$#C7Cf+K#zj(i99mY?8Pl!SeC3Dk(sfzw($%vLp#OFI~jO9$~u7i!b{!^`ygf7!rr z+(zbUU!?0c$GdN!;<-D%= zM<3&Sui$=a3T+Ju=Wx7GpgHPyh*DF)>Mzb&>otSQIB`TV&@QvGYrG;ak!Hj z|ED3B8d9U++=Fqp+C6-Xt9kn$=2qnY{sBL0Xr!h$(a=ndG12PTiZqzd@NTW$HDpPv znAhrNEck8>U)7LI?apX@O-n)5xFrjo01ZRZuyUEkYJG<)6k8yu`h8pdCZeGLdLY zjr*g}Mg|-$<-gv31?`|E4RAOEjb9AF`vUNjR=uGids=@_`mg0R9kr&w)G$pA8P`-k z4*dNa?)fdWM{R>rWc%sc{D)zDq-di%@tCNiM22(RdGy4c7XQrfAdH zwjy>{9<8fa9ceO=&Kuv+8)pr%Cl(fEH z@E>knRBxeia9WSkT1gw@GT>T!SNRKpRztZ%HkzOxEJgB%+mB zyekXN-Oce_zlOUBg+ztHXqPE?JwRJ!VYaJ)k!mxM2%p<~aG9Nia~*)EKbW|M)gt`s z@MM?9yqkpCdpWKF?nQX_Lipb72OeD#F4i@WbBb2Ohz;%tDPNn3HRJ$tHJtn&;>ZO^ zluZy%_}aLKx+A0rZmHiS|9yt$?BA?Sm#I(Y>QG7YAwJsebDVXoaEY3s9V%fmx2m7EeBMBbL37*B^? zj=112$nBk;yaiczvV(1pU2&c^1zR&J2+eIvq1|@8ys2ZDyyK{PgwcJ(R$$H;?q+WD?nOYB#>U_q1<|5GgeFoG&bJ z=J1utyKGl(EIXX7!|l*T8*=rlS)WqR^&)M;=UN%1^+!ujEFESFwoi~ImQ1Wrx<2{V6wb zEiGtPkeuHy_p&`n_^j?wiXl6H~EuY zLp*f~R}{n-K5~9@4RfH}C@)4&7n#*H zyHi0&=P~bgIQ1=Ow-G(4rU5S_Z-kXFjw7ycz5KqAW9>p#?}B@t((d*7<86n0A?kDL zFjGU&pr)5mtXE5mau{HtGTw{a_~rq#EG-pD4idU9n<5rr3C z4tX&xbBkkpVX(W4>%M0`6=q3~{uawwJ{X>d@g?4ebWr(%U)ZN!aRp}W%lMq%o#&3V{vP*naQ=yq5~bpmagIfiw;CO2Ax+eS0FFqsuU%xs2onx9-kiuCa-g8EZAuhYaGss^P@^jr&1Xeii`Az7~ zBv=jy?J--~0Aums*r2lPX3q%s-_myRo8w3Jw!Cln+;y?CkSJ%cA5C$lkK9D=gYlPX z5Vu5a>V1>3F?m<&eweN|XK&hDhgloRbytR5w>9*oSY{|sf4Se3`{>O*=(wDxq%TjO z>TK;#N8JwWXYLu=zHFDW5mr_z5JKo4^iS{moS>{oH`VdYR$7>Ba9W4@Pt*0& z6z_Xk$a;9Nl~Rx0i;Xn>j;GAYm3q<2!4xu&}H#1YrV0;ByAQobKJ zw!0sBn|p?MYD(qkPP$;@U~{2)mhlsp%(XRqFm%-a!7c;8^pv;qtAtl#bE&7yG%l+Pb;Q(|=hm z2mbQ^Y@A?f!W|Mf$}Vm^p3{x$T5*-{wEacFE0>?}OPnf9<@5M&zIl8*r99n=>!drw z&VYmd6J`__rQ4;eum8dhrFtUa>35(CbJQPDH(2DlVj?o;M~IZvS+1%)f*bM#xd1Mt zzY{y*-oAi}gHy5rPOGiq()&$`@TM2MaSmk$`H%5SFx@eo(PxW3&sOS=ai;l|VI0$o zaJgp}h_<*w+NX%!#9`t_eynf2ua#gYR3BtwcXYPUs%F zx!RMQ2~1~%JVuD*?|T>fE($*-aLmdurK6Gs7Vk0M;icdONk64>$W3H>@*vStYFhZZ z;DK1y*w5U+^xW^OxerDA8jHoLeC~lURdF7CDIMLnBTg%ghmwn&89RJ;SOvR6a_N#D2niUoqj8V3Z9=JxPZj_-A>OoS^)MRTo3)>0D|feS!Ld zRFb*WcJi{=rm(s z;O`2Zytlp6q%H6OeZbDtU(;9Bzt`@nI0dt*C-6v%V)x;~}N!eeO0CLLUI ze=3_wqxw+QscT3H5a1H|oBEqFkl*V#>4*`xkDI+H!9i_l$X{h3DOZKb|ENNNkVtu34+ zFTh<_QNgP#vGB{^jU8Ajv5S0<9EbYUb7GrZ!)tNuw~zCjQiAoSz}w+{i_u}dEHAk} zL_1-T>sX=FG2PzJ-rN>t`^&*QJYp>~LD$MS#Z<}fu|I2hZmD2tV_v0OLjEq! zcQ-1m;uu?4%kz*glqzFKHv*(P~p6$MYQN)@69JR1tln z1a{OskkbfqF0#OXGLIRVUPN_3X3_=exY%A?C61FW%T1sg>O*#-zES<@bM#jFHdUFp zD;{*;ws$T3#J^*r18m{ z_aV2#N`{UJSZ_+#@ytV}D_Z&r5ib^ZOST31b#0xThxq5}0s1lf5p3QbVCW-t?F<8r zmB1(*A{vMpo>=!f_bBfn^z<2G4RJH_AYzG5%tpQ5yx;Gdxt5^=lcV;Q$_PF9JH8vf zL%xx|aDIyL0%K1!wS+m!ego^>0l)9!hH>!gRX+(??j!bbc_I0y-LI(&mb(!HA{&MU z1g$W7C<9V}HwrPXv$^}zm7kZ=*xUt$r6iGD!RT}e#w`C6LG!|AMcfbW?zfjNA=*9j zJWaiwy%#-IT&o<-3wwEN(g*_L`+KBH2x#W6hzK0UBk(zW= z94aAKmVT`_nHQPj49B=ErWU&as+yUK;JfM??fl{#<82|n$37G)a-u#J!nEQ3;zqH} z=y*~@BF=YkJ=%;{;Ct*|<1Fr6Qp+pjH7=j5D@Aw?*&gQ&&0k`_>mDZrC~pZH zovT}Hit!)d&zgsV8+-%z`lr$%{pkSfnbpWDl}*Vi-dHU=2RvUA9n zz%mvfUE_n=Q2djR;XnJ5#HO-cio(-xB`eac*hZWixhAdQx!aK_ja~dEWgdKQcL6J? zuC$V`OP!>V(hcE)KvL(7qb&`Cz6LZhcQc0T+Eaf^c}^vd%3P6AE_Z!FdDk;O3CFHxP8u_uKlj!o<-ize2CJYvgpbf9vZF~>gt#3 zqPWL&5-~`2BWI_EucGgY_osJ0)*D{1H9x82Oa^<6d&B+CJ!Fh@DR|_cRhk2Vcq#XV zA9j7QjI>T(C+Er?z;9Hgj?zak{@ckoaw9O7u^6|GAkQHL2+w`u1QN{b7~?JyIY@E| zRv77+cpe_~#~3}A3|{pXJ&nG_+@e=2`NBxA;OXPriOiqczS6!z;cwYN4q$#TiA)RT z2b<27*FENzGEXUnipDFHT&|Xqw~32Im$*ziFWr}(N}J^|su#ZaU&!8Ih^*jcj^fW^ z@Bu!cJXQSE&q)5LtvHcaeo1Ksw1opIR)Y+u)9~5@etH?k;yvmIWuMYi?jzNdtIHwE z5#(KjseQ;MM1Arwok9*IrqM2F(WcPX)nFxsd?sB&7F{#RNt}?{qQ5ql^~4hKog4;i zY!$nKTtm;L8j$63q*e8q( z70-9-Ex5yNND8Q;gkc_zRBy_5q;4o+>I0ODz+aQ)Pe`bNPLgVlZ1Vx6PmKq&b_Mww z!SMQ>2Up+Uz#?U-wU8J$9G=B-Qqm$x8o z=Y(ParbANEWI5GI&Omxk9cl^kRK}@Rup^(yuj)>@3jEgd)lp=oG6V0whO7!+3Q@Ky zGpK3Elo^IqS1-C8(~w$8UnCB}mD+`L7JsRj6fK2`W~BENQ+FZ#M}<6)yPakg~jk(sEimQC;Qr z)O|8Tilt{mcj=_Rq3z?T7f2@93zy|EG8oBLQ`MJ9zNoH_C2u2neJwdb9!nM?&!Y)4 zr8TAhAJkKMAhC&gCnQ55VUi}(LzT124$308qMj;y<>OQj`3ur{x=6*LS4ty>kewtC zwH52{=kzh*w3;PV6l>^SC}pWHx_*L}%4Z(QJZC1B%FD?v!bN15IK=OYK^P>jRSqbN z=u6Tp@USPPqg-pcD)dfv`8+ii8mfkjS?&h!{B2@I%*nfiG00-q*y~84JQc%4`P|H3 zM0q}1S4|3$-?G2+Jl&gWDAec92?y1>+#2s0Hi-!L4KSukr}@{0>yjT5;8|juID@`V z?)P=Xnw#~W;A)b`TxrHXh+L<~@3Atcu$y&{4oi*kBfMlCX8WG$$Z!a+^$elf&IpKdM_Y2#EeOPeSV9_mg{ch~Zj&wfp|HYJZ z*!-^$mz+W7ozf%sJuX18c^i>eq#OK1cAumZp6d5WifBHiMDiODM~5M6df}&-+Mha%G{}?C4Xwdgep`)34ozo_BMX(@$XCjdy34&VZvLiJ2kV>y zcl8v)pGrX*l%5)i_MHWuw-uP|Xk;WcRu3UTZZxhf6xmU`;Y_|>S%6XUAh?ymK*#6f z_pO-mcH?_yVU4;B*n2K`t7k|_Q=zSXhimEvc76a@!OF;AZ;$!(6Y^}5kmgel?(UDl zMpOVRTo#PNIdv9R(?&4JG}xs~;QAZDk;@pvFUViyt(b@6$a>g44WYXuajXM;*)L#s zP!B9>8O&4tkl!)~8p|Hgkp{rOeKh#$6r}ew0A61eS(ky(+HlaD-UO?@8b|C7U-e5k z!f#NJcLZPe6Kp~^-2WJG8Ru{(yCYM64$%Auc-I9m5){~rR#@kE!>;WL7?Fx#9Ew;l z8XR3Nc!KKS3^f0O9Z&|W0zdfjKfdBBJ{b#6p$|Uo!d-3v=DiuTxl@ofaua%pKasO} zlnkaDG7Xtzx(iZ7$0059fV^2gEnA^@iba~+7r7qBWu!7<$AN4#>@7M{C8>DoE0Vuz zBFE|w=IUNVHL%>Dz{9M<-Yynu_c74BufSET0v~w=N_&l)I0Y7RKXedFao2_-&3PAo zrJ%=7hkoNY@t9bTcG2of`rzum{l}5{kau4J{3G$7FMJ~2e;VvbSL7UZ!*vYDJlj*f zA%B%lN_(XjcxI20Wf%)rTX$P`imT2J1Co#;T=9PO4i)(vm7~xizx;CY>;{pv%@-Q%058d-UJy)ad7iDt67-6XW$B|z}bE-*qc~5 zw{Jyx;bZLnyF;3m@)rJ+yOt~7IoA1)`-^7+UsI}! zRFf!j5cL}}@V2pka#=d7finy++|%77;x~>5Sg60z0dH z*lX*N#d--VgzC%>`aYFPbX2FxHKjZ;Ug|2BKswYfu#|nlvW-UiSSnG5tV1S(ty+y# zwm77?%_17&ISM2@lii4H$>Y7~df{?-oWX<$or8^M1Fde$B}(qy%2wM15lZ;x6k-nf~$L6!^uVor2n zMdfEeKq+^Hf=Z1_ZwNh2KhCp#F8}Js^En?L{504OOBWflakO!~!D0I1cRr|Vq*T0Y ziFM&6{I)1#^XvUQ^yT`OerY@GN97X6SpjK5qXO)v_WB0wXhz{k{bF53CRs{#uFMYj z#r$$*#5m@u-~4t(_(dm_7#jA6*+q`@y>hVjw)UQdX|4(0(Ly=typln_rfYCr^k)rM zjU|lD!9>+%<`TC&-i&WwntzSR4B%S?GYQ8V2GpBUMIV($4NtH8vchE2iYu{ys6e>gVoh%bahyI$`5u*2f);{v+(G`3&VJ?kXIWpPbVyyL8?L zJL{dKhH|saH!ME?y?&x$I%i-$5#_K-@Syi3h&{Zac~er}{@7WNOgAW1r?H{MxVow3 zcLp4=Q7>!UUYeNpeC79#4p~m6x9XBjl>+&wDe+yZ##iVWz0AbeM!mcAKz(F>ADE@1 zXBMkb=62b)(Pe@dy@wRlFlC&y!RyR>{BzKk(O(nOM!E(Xenl=QZ7MUV#ODAv`;Rou z<0)+AAnbqSpU?YgyW#$%G&IZ!I22+IsTwffxQpr`wf4SrR&&Z=*CJ(}4AAYMa_w(Z z|H_E>o;mzw0a=2RF$YIZ0T7McZ@%kruWZK;C=e~^i^{~*QyB7JW z{J@G$WBUX~kbN9uvm54IvCs6D7Zzi8Ib1j?m!#k8C;4x)?yy`nKBtk?<|CX|hiI?w ztj=#DCmQGb&$h1fA1W;S{xSJ+#&vZ-siw_NHGh?0EwNat{I<{aOLz0$IWh|PLVb|2 zHGP(Q7O=i}-?HQ4E0=t)AC}kVU6+TYpDp{^+jZ6Nd8}BmY1w(jK3J<8{vxMIHt+ZR z$RBGzp7^xb%W9k|_nYN*&Y|av?;m`A z;m2sPO@O0Vbku|J_`vFc385>4&KQS@eKT6UZTx)vhryZ9Gew*zyQ=hwVjumG+~Rrd z`rs;X)^|^j!G&yBD|CT2*xdUl!JjAJmK>lqw~UZyE!&0ImX4-{?-(ugWMxcmQhPd zTA+h1Ctc;O!b~ZV$YQo2BRG^>O$W)(bC?g?J`XRP7SN^Mp>|;n)|C?t^M2I0pLM_E zr;Rz4-Eo4)^M}{Xb}E^ZaHq!l_)6Bfc{^WCePVhaos~#gtZxFI`42I4G3NwzDSkfE z>YplJ{n6v~q_=xhuDW}gE=0DA8WY&g7)_leqG*QMLvHfDE7+DjJ9nL{B*pm^Sn|x* z*guu8;%wzSwT5xhbBS!RxWI~M*-GWb@Cfw zETw;HEgSh)bjR?&brl?UKdNs|d|sF{jyMo7C)^o$(>Q}|Mm=R485-+OE5!?Y<+RKC zTp)-`xbtRau*H!NIDromGNk6@1tx)6Mo*&GlRDMp%Suc7FeM#z zjM2X}d*7;DwGEMTedFGicwl{dB|W*Ij4RZ$(=k)d3+-B^W376X_C*k`y2-U(MI_zJ z+M{eTtNOO=OK!csLHLQ-oM<|5yU^~}d@LZxXW>}p??FSXjIIy$I~%6o?f1}c2>sa^ zm_06YMD7T_C0E)w!k}X&s>84+y{7Z%MsedvPK@GNsR?qMdQ;7SD?cE>^D@6HRkL@# z-}Aj4e>k#Ri@9xU*6dp%$D8)L=lu=u9%kQgc6N7mY|AU|n;v{RVQamWRc95O>0I&t z;EO*$9?P3grJ83kF+kNN-O9+Uvisud2S)iqQXagfKQGAtn~3$#_aCIsM2%HB{R&G~ z&>PDxqD4WY%+lGP3!cbzbX&N3^a&+WUaMZvk$y)ELzwUK7~ewvw0e-@k!6+%9mpqK|NcleVe|mZB-72-pz0QjC|7V+Z{)mbEa)n-i(~y%A=Ty^+(s8 zR{pbDNImefWm2v5-}yJXPF%b%#iOGh1U4=Eyu!Q^o#^_RbCVx@SeU&|*=e^){EhDUJNN@L7$IJM+%DP5Fn?lQQGn zkAt&nzHQj4((0h)cE6<1W-6tjloiAgqbfBb17mz#q%iNTxye@JT zt`T)s@b@iM+8TmF4-~s;{YZ+A#OxBb8oU)Lt4YYOKkxY_Hew9MmnNI8BDDJA#PgU@#-eMq|Pyb&ce-PYE>_V!|J+;5UUzH6PLv$KVPsV%=J zWyUKlVwX2;QQs8%jjo=t=+lez!`{)vAbzxMWnO&YXrnXkXysO=Us*bO+N8RF#W~gq zZIzAuPN%DIwvubHM$|2~!J4Z!cFr!ya*;|TaZO(AUFm%3-KTy*6-i63EqN0e)9dJ} zI!0HQzAC@)Rpl#4pVS-lSM~(G&bKdp#QSSs4a~`^!&^l)FJ7s#aY0V(*Y+vp(z%>> zzosOe`2NWIM?`Gx^7X0sc>T=$x)~30d>&OC?cSJCKEvnkU^o)nyW;2AM8A&w>%tj! z*^@84cK(~UBBz%pjI{ zHvG$o*IEbE$CRmEqej0NJ=q22?eoM!KF3izOP5kBdmI@WkzA^HiQ~chnGtd|>TlvR zKOuidMo{KO+jVALfGa4{vX|ROmR29LWpqbm&Xa5JQ8>(Zlf2ALB%1>9U{Lj0lWD*> zpwVkdy{8|sALw2RAq?cxjSQE)!b_o#EYWcsq4@00elAJwmixR|tA@6EPb%yT>500@@$zJw{Y}!n zZ7+WRHrHzld{x31VF(=&;S3?oGn6s;t$z&p@gOh9I}k~s>x?@Ck3~cmUm2?C>WHJ< zHw$~(yV+wL)m=8}oBp|Ft^abI-;CsyahZhev-No2blrfHMW30 z02F%`xr1s?9aCk@H+4mSbrD^S-Ys; zv;AM^#)2qgcdFj{Oa??!c1hI>K2Ep1@-bkl&UpDP)n(~F%7QmoB%J?(xUWfL}tLxQ*fV=rJV@6q{!pRuK8#`nuOo zQ)<^w>wYA-+gQ|?1Er@%?h6_do)UVJDU%=bGc&bnmNS2>V}N@-?H7?#%2;B0@F>f0 z(+wt*56)ejIwfO~&FE_24w9D|$^<2Z?+!m15NGgmqlsnCXSsaN!Mq+e(RGhcme;Wc zbE;WyK52et8mS+^$nsU+Qg4_`$g7bS^dmg~uwReT(NVte^=1AoTRUcnrMi3QuVz0J zf9?4|KktydBR7e7?$;~uY-nD|cNI>?MOkO7hkXZJe9rwJ#lP8qO?6jiCmHk1Lqe)V zcaH8F`r7bVDK3=ol+5@1nw~zz_QZWf?9Ns*Ct6MgHwZmqsic2S)e$qDU9& zalHJ#?bU&IgHi@(wkT-qnL&jH|BBsOs#?^Nh?U`2tS2bhxiV)$*20|cIRkSJ*^A5D z^u7JBTPp_L4So{*%~HU=lYa;~Ue(qvcd~7!tGVYl9v&p@a$`Tg_NEW|R6WB5s4@IU zPa6;ES?dY$T@+`MiL94vsehnFQ@t6(#KIrmO+v8iWiG0Z#W`H~%zBjB zEhjYZWA>%&^^QtV%77==`&qUGuL)Zmyw*S3+{bLwA0@ksq9@F4a4&YM_LYt*oJ@GhYMOV-7X*&C`P{zQ{63+*cty%lPJx9=B4epX)Jck@`$KE> z1I)o%pnH+1s|itgIZr++b&$q@E6b3+D{0{DF0;?s?d)!L5<7yKi^Nf<)K|PAGzM}r z4;a1&;Ag;Mik{6rk3Rl_QEn8Hd`6w!rYmks;JFXq{zfsiMih zfI4?nS0iUzMTOZed4(*LTjXa&Y|B@Ghwi{-GF<%~?QGuK+Ku z4BVN+eK`fx^C|Q=8-clQBYeaXAcYpn2({NvvK!9vGOF7S;yN_`^DY!mOM&9cN@M8M zFG3Ts8X4_cCEZitnwNp7zXjg-TzQ2|?8#tD&nvx9hf)#z?JuGOlx97UH~#}HZ$q@q zR3s}G1OFHaG`<(m`Dbbj5Yla^Doet*okB%hY1CS6fo?7w=Se~7-T>J0Y1ARq0s_1o zl>vE#8;Jc){QNsAR5k&XcR)dsrsRUF{S9n^hdq7>@Hx0ao1;*nK22 z?ppx8J&gK<(%{mkgGJbkd2lr`0~m7xQ1hF>b$g-Ot_r@ZBRH3{z!OUo1Hi>i!&NpT z+S5_A4(gi5s$H^C2g%<=g}jMTe+M;EzN?m}wkS2oba0S!$T3JwJ&*k43seF4mR7`G z)Ra4wqm)amrR3o5zeJ|3og71tQ`6}#N`f+h$`kXDS9?Z=#}pW+o8V+xP!oxd$nYLQ zUL>xlSBQ1;cyL5L<>_!ikd)#;w3-vW@h{teI#0kk+JUB5BTJH~rNz}~l_xA%T@KvF zLi8;oIE*R83nbCLR(q>w$u_9?%OK97e&ZpkQL3s~^Ao$Vug_HX%2y9SNj z^3%H$oq)_91;=H@IW))pPX&9TrG%s_`%#le<36?lzCZ83%Eo=DV0#BuW;3+61-#2k zRHcjp_p<|d`ZLsO#1bdb=XQg+o`$D(1=x`J;66T~#{{Fdv_;SQq7(y5bR6{>3vg%e z5dFzxaNLPe*9iN4Yo#IJ064-yE@1BHk_^w-hhW8uF)yf(a&sZuo9grMtZ%e?x4Vn* zNdByNkrKX($=BuS<8&Nn)`{FI_6gXrV5rUp$}PnHd>UU)yez$hQsb3!g;1zP^eC&r?6YNR)#fx-~BI{ zR_Oj>Co^@ZAxcNSy+`(J^nLKH^!?x!=`rD!pHt~*ehHm-BGRq>!v!BX{bWCi~FIRHwZt3V`3lawR}@u zk2C&BcVNmeKHOUiwF4|;g3?vCNmrn9tS0-zX6&naftZFlH{x9_&WWz}@Q# zHSbIHD6}D?kd8eKDvrP8D#t`n9Ek^DH!#0liDDC7IdHZ{lrFURV_UJa4j`=qa z@U!~#D~Pt@ci%%-J$s*m9R)#!^}U;gGSWpQkshO;ZHo4*VZLv?YxqO=H>P$?a0uwQO|QNn6l(^WtP-Ixa=G09pjDQ{}yxQPii)~l{T^_ z?ml}7JJVTI6gf%#DA$$hL$$L^%oYjxp3;Z7gSw1LTuJUY`id9hQGrrYsw#}(#|e+b z^5C5|s+G~-`q8)0_kU7e^`JPzSHd0a?jZ+p_jCghfg)NT1}?RnW&akxdHQQMk#wTWBuv>KRTpEwMDRrkOh!9&xYetJpbZd;jrl@LKs;{uSRrHiVFaEX0 zh4u^6n`g?a-7TRxG8B%_znnEbXPM)rr#atAlIaNZB-^vJl^bk0zQ z83rt1m3y3Lx#tg0j<rcH=~T2@M@r+T`eOJ3L6#)!cI!dA z9zotg4{t*rz^LCI`kYu~qoaOa{YQyZp2(#!D_18TlTT3*mLPp|?6!ZE{xNLuPxmWn zj5Nz-c>mgSf~s7&z63B+4cq2`jimDAE!X`>t@_m}&F ztuIi+)Z20k=yZayPT8bs>pDU6*8CC12?c&~f4yNmCxkT3k?J-$aiGmzU6YH!NQ6u{MM53`KD$+kf? z*}wXo`uFJ1X~Ybyr_N*D2hE3Y#;5bm@XZox;OW|+>d6RH$!YcTZEz(v`Xfb>m!N@~ zro6x!E)HkiL=91QD+86&$~q{qLP$4Jj{FO&!+6EW*Y%7QSJFAGfK_u_Mw zEKmI)dO_Vq%ZnsYv+OZ7sKDi3d%t@>^K449e3CE^! zSb?>LWxpH*{`Uc94@o|A}ukH+I;tsMmnMAr1xa|PU zp-qS#$_P10nk9{rE=zw)HKYpCc6d)!Mg`tGD0X&$<-UM*Cgj{upe!Qa;%-->vdOyG z1q2XFu-^QD*_wmCWgcoS2SUA&hAW7GHgTgoPC6qWQr8kZw5^S}Y~-T*M_E`Eb)UFPKr=nRAN3b1KEr0Kz1Rs7xy<03K1iG zEF4N(c#Tbz5~R-1arTz-Fyo9-GL<2yXWa}Qei{^s*KoFhsG~iO7W^IS=$cp~mr<9X zH#}5^V@2+U!eIsey)vp_-(o#?5i7MEtZWCMKPBP1ekik`M$l@f|G@QMfik2rbR1Jq zCmI09gMY9ljs{{ypdzs}=IjyJ9WdB2RKtqgpDd2`XDPBA^b2307JrFKnx0r~2ICC0 z+Vn%%L9D{+awC3TfPKe&s8}?QP7cqYmOY_)1LtDhrg;x&6~~%8tX2W7IsCrD&suK5 zXRJ~ig0UZrp3)cV^^WL0hW`{MNARs@QMan4_ZG)$H6APUr8v`IoNq1YX0GBK7vgGf z63=mN*P+!2f=2!@)HIV&>8mM+IQTD=My2j&tn1rh^_=<@;cMt6*Fg9pj&wBgXMxaot#utO=w7CIZjuZ3 zWhw(qI@Qa{d?VRN$i4#slj!062wk|dvEU{;dt(fCvX0L|lhSCVz0M(2RpBot`NO^L zpp;EbRz|V^s3Sy)c_40Q#!^pw7nrl+U3hktlOE6?gmRAhteliu0w3-{ z9$~f%Ysg&XymW&)DqY4*ks-&kyP$d8&baxdy3g`Z>8HM&_Y1q4pxtBr=D9P~<;FDo zR`U~Kly6O77yDbbs$rJnykAxRrSH5s)H6Wk>3_ryWG+>fXbm^EO;DvRr04o7QWoNY zKpPs$m*o^TPwGUqA!yZ1-4HsF<>+u(n=Mn+PI3t9!D5AQW*hxnC}1!@N^7qoUSQ9m)NWO+t-zR zCC(EE8XAgEl~_Y1iDEZ#r*URK=}l5qsu4d|dQLTy#t{Vc{)?#c%yIUn{8Jfds40_5 z9xJ(P$ny}<_nNXuEr>z-abCjzxqfRwfPR@`^$gO_^!z5a*B=r&dJK7hpJ9H+%=9i` zx(Ir4rPd4KsT(Lg(H&Hqi!9Ys-T-&Y*HQ@8RlkaOfIEKMxgHL3ulX!8UV1?;Hv~Y< z<&_Ome>w;we-w2hiNYv1TJPD zTmj$sbjp6JrTmtBFW*o$!a;5vT@!P68sj8KYwi`QQI1wVNv{M=yZ;xVr`HnSs37$P zS)1M^O(5DSZupvJ$ju1}^<#fg&B?>ikC%h;w7oKs_(R;JZlasY7n#*`LuDV6sCva| z-j1#T>VA2GRF{KJoj#{)$Tp@vV|9EVwMT!;nZ$Z>I$WfxDE~-FQY+yN_=9W2A}Ufz zCfhOB;YsyQ3088*F4O_6^?pL>S{duryJQ_=9p;hxWPj8cb<&U_>1a)zRR>GK>LmV|`<{2Px3-V**6|Hg zOjxA^>drxRH_TYizytA7)iPLSY&`C*+;d31u;KU@KIYbb;(hHz6)VbIXu> zsq!kPJQHQJ!z(7lA4f4on&rj8L3a!HLwivGa1@*{{V%nK<<)f2!D9mdjEuWq_^-; zI4<0TmSYEVjt-;CGv(Mo8eUd%MLd-W#4l-^BPo5SqrTrb<5qW!GTazv*3%v!Ppw5wI=zr4kN-uPTX z>>D{xwdN$!(dKE9(@F=LyD$@}9K(tdW2wczj@i3AmlfLGWmBi6=(59X|1hCcibKcL z4(u1atk^9}n19JIIpFt@8J64pd8sY^w{Mzrd2Vd>AeXJMnlsxwtk5D=Gz76c(}eq1 z-#&1x<(7WEZZJld;-2~+Yo~0rys-LbCl`J<)C#N=doO61E=_+}eHv0Byhnc9%pgy= zyT0c~MwxGp>{+?veFt^#e4~6*%`Jk@MMMV9Gt3H^6g0pR5EMw=7LGATDNI4O^I3np z*ZI1kmUd?09`{4420anV=&h<~>SpnBdE8-cA6JR1Cr3Hl-{XEvG=)U5j_91`hGn6b zN(~J5s#%6h^my~kV*6b)el~YJ_4E|~%uY<6l+(e{(DRC`t{nCq*BuThjATN+%timL zp%<+tYaBCOJc3HZJwP_DxeLHmbeg0^0=#PrI zRj+&Fz2VWkK)I?DgXes$ozu-4RW`g?=Qz~**N28HTfEd?R`$~AA=N8l?PLEa%Pgy# zh-rt+V)wno@xg9>akMlsA)X%zR=;v=&B310hZ+yhyyncc ziK`m_*1Ec2SXz&)J~`9UXVt3;E;#k^iN0l{6ZI>b?tko1|B67(Ik9_dzloMQO~YT* z|7+vf86Rc5Q~#YN|7{$^?`!Ij(xyy5V zyO-s>n|*s$O`ZQnc9ktFJ6u`E%RarkDDBkCRe#2&*S4x$lQ`qX!#TMt>oiDjk@ZvV zRr#lL-wj67u23aTr{D}#G~Za;vubZdhsBiNclN^S<%xX%Upk}wdG|`~%DhG=o{kGo z34NHpApDXuUwNX5p^ky`qi@wrsc2O4`st}oyPVIX9>UPeo zo4p`0y{cK|#WfS1DQAWsoP6rFs)E>vs^80Y#eVbFyB)Kh$mo*xW%?gEPv+lV?{DGW znT@iqtaE3$u2xBwD0lQztfbnlIHzKbPJ|7_uC4wl{<*U%Ff(|Yw*@cH68)>5XH} zYp$(+Mte%yo>+e5)r$8c_tiEo%RPHu;sLLj`(Su%=$_D>8ExxD8WhwCq@A1db#8v0 zKZ0BQh3>arX6)J6shaAuT`LdPltug2yjfWgEzp^Et+b9cInXKecxXiUmCyxRY1*y* zzvsIByvCyKUsZKKG~O+GxU%p}ymEYaMAog5dDW9L%j?gmw>Lb|*^=ET=UDKU(6`>w znirI}To--&Y>SgqE3WefM21!Lu5KJ3s1pz7c=rbPhVKu5pY>wSFBy%}wq#r+I#ve@ z{Plr7!4JK?(e;tyNT2A7k#iyiQD5)d5|8-l+Hu!fJ6oP|IRmc9P1i2@#>%36?+gs= z4c-<|MY;CGpRZkp?RZQMtpn}gdGrw$C9QiijYGsSyX>jU>I zTRKm>MmGAc+g9i5r+X{?9_|O)qkn}?w;HV#t-Jk?lpo%vm9EbfxdxTLr=Qtd%ILhO zO7)+$mhlg*fSq#MyG7dTuvz&BZJySiio3Lfdy7uHo$6j6IPUgxKXB&-HU-*fAK?l; z<07ZRdtK{+d3wf4|4Q%sL_1~L9@jeNxWss!Z@EoT{}QjzAFTYrZtYAcaSpf%c`WxU z;(bmTh4$`C$^g_l7r5iJ%dLmb!W!)#(f*tM-pk&PT2K4c+oSy6=Zby~D%LrsynPo% zWD%{+bWl`A2ZrW~fLrUY0%wmR?&lQKT&8TpB%M`toBKrI*1${JIgqP$&yQW5j;0+Y zYZZU5O=Kj#)0vt1u#cS&+$P#@GS+=T>$N5By@|&sIg$>;pPidrRI_#-Xd?Cica15rqoHEoD(!X|D~`BTkWO;uIUgu5GE(nx${}?U&aM$B zkJ1dg>-TQTsgx`JU8~nZ?RFWU4ALO2?RC>C;-%W#G+NkRCJv-aM@P}^M!oxLlopDD ziR-OD4>3OdQ8E>K)A^a+wy7wV!vN`=z_f@8C^Jyx?UiUs&vX<*(P?pL$NVsM||@ zK{_Z?@V@YVz3`--z5Wl$-12H?vT`#y$|a8T_c~8%zm&2X(m_4l)y~!=#kVQzz{!Z8 zi$gtSuTJX92b7PxM^d?2GE}0Bx-vUj9q%sMUgjJY9vaHyAFUHgM>#oKxt}P$?c^-f z>hwlY{AsP=9@ZEy`42lUXr(h>*!WKJc!gHBb99o$1i@d@E&z|=_nb`bmsf+ z@BKwP65n*rq2q&AT}B1xhG*;a`vW?w=AieuvawsDmnGf|zUa0LsLM|D^1!iBQ2Pca z`G2UZL+?;qK_im>EfuNiNT4(-UEqEi2~<Z!{g#c)!OZPHvVwz)7zDueXB>Iu&A208KIHm$NBmY&U1 zr;m2BN?)qh;3m}$T%q14og>Z5s4HunH7L9?(I?t6yfwFH_KviE;qh8!n(4fl_(N8+ zch#q*d&^&}emGhh-B|ryZQO4j=ob1mqcG#>yRC!oMK3v3eSCW?RySO)B<<^%&bG>N>KD{a%bA)eWYi3QQCBTsq#f-}RJ;d$DTsM<4CVNVLb80hX^?5_4#Yqg~X*V=`rOB*%)pbregW}=ZyDFP{eY`hHCLOr(&$XvA zV~@u&$}gyHzf1)OsZa1!=3(-p|+`o}x}KW2IY4{Xy}+N6(LTj&4kB zicc=PzWB;RgTw1vy`O)VJFB`*MwfQ8&U>hCx2)WNs zqt)LXtEe~_x*>C9y>1QG=6&8Mmb)saSF?sK=G7hUPKkV&sGn98KU~(YZ0hM|rFT|D zD=w=&9=W^nqS|m^kXCW~rZ)}k&G;s(MaD~+@1-9J=;VO-Q0*7LB|fS;zj|NoC~=t^ z+i|98(U78W`uz6aH(TK?DIXZVtLy2DU#L4Z{p&=__6vL6!THK{_Kv;aT^i|jwtjVK?JM!2 z@waPN#j~9`)#o4XTzr3cQs*aHmPAHZU0nC=?k{v08!iiU4|Vjn2kxsHSaI-l-)%#8 ztUgmv9XwN9+~?4x!Ep`eW<65pow}8I-I~3czq1_L& zaC~pglFI8VXUC>!-Tc9LY3;Qq?>sa=zURVD?e0i4Io%|^f7d?U-%B4^xiauz))U!X zWB*su_Qaw+!w!5=n^Rf$(DuFO9`9A>aDzV+8L@pCtMZq&JlJ?nqhtAB))|rGHQblG zCwSn@sL~sCPC(VkcMrXKd|}n|wNF;0Rh6s5#MI!9%x>9pGaH2b%!e8rsr#vRXY6&B zgbV!}YlqgXs=2cElo}Y8#kNHsjV|^-3uGl8KUG!ythcoN&gLu2-!E^U`&rkbb{!(^ zYO``%<{Zi1SNqtBd8f}5-E!ubKj`S$-#ZlTs{W+jJAUls+wr+|M>d((XnfYxyq_Co z=bqc-nkEx7ua<3{7ha$F+u5bZFFHN5>Tq;*S*Me+@~^9I)5#JWm3=?ytxkJ8@97-H zD1nvf={etItn;o(Y)`!F$*RQfsLiiAKhjrgWKCm}YDbl?IXboS_kwSm-BVq+Y)lBYTmZIH*@IT~&o=7u1Fm_rWVW ze&p%sbs4(~de?u{Z<79~R^V^W_(>k*nCcEE-N=2h8!E0o)&InT>Y~_RYOapY@P6diD%d84DUa@~S~w7lR`?s9pdz1-&hroYg*GVpQbQ;1Qt}-*yIOhIXRe$c7Tm&lJU(2o1{noYS!1T<2fvFb16<#S3#u5i`S z4ZFLvZvTPoOHh03Kb40&OV@Q(jb=~zkW|8TQmi~%5kgRB^Aspf9U?z`ax%Ibo{VTZ z=<{`o5Oi{ydimY0*-z9cQxv;!_IbY6!$+xF@OiBWPn5mCQ!!3JHKU6a6W^cg{r7O{eGg<{~KeDKXWFJQjLK~UxDI-bE(SRdY`YglRBp(oM}yhwA; zQPkR2K6w}2(M?ZkshTuaIt%qJ>zf;OEi06qUCx^FPQ_w7^ywOnwolj5MS)ddJFT2^ z`{~+QAQ&#wm^}nBCzrDlT&__z>;7Lgg8D~@6SgTZx>zEpV2pHunR4vP*IFdc{el!f%aYA+1g8Y@n~4mFlL}PAB8c z^sh}6s}@)L`lV;IZm6>`u2sBvizRr@x^tU+ z-s=ME6lZp%kBBog(9gNl8!vx$u&T1Vsk_uE?-fOr#foIFRn_lg#n3+|7W=Cd#kF!0 zigacxqHm$7Y>sGtQQ$$XcctlUmU+^Fvz2KXqK+xM{3+h?WL3l;I_GY)=Cwdo=1ct% ziY+>MYn@wEbvj7W_@LX+sV6)f)DFeLihVol49szU9qj|0>pkPOcP6UxYnPwpE%WEO zEuCiGU-k4OstCGDE6%fn)7%b;jyk(5D_G(!R%P=aI%`V5HXH3jC2e!zD+t)evvFR^v7# z#_MFvb^anRqBu3+z99Y4T@`;91@3SkQ;pJ5cY!is(-pf9cV1DoOt$kkW#kGJfk%|1 zTj8ydzMCN3K1eyGH1W!OeKSn7-{|jh{^72acmIg}WlP@KC&^!!ZO9-X_dy?j}T zipbE!e}V_R^^s45|IYYW@E!?1lTjMHK5>2U+u*juD~Vz1^7T|aFVaM(jki~AYhk2^ z_qnQcF3{L_hTjTp2}}$7;jD1m(0jpgq3wYZ>Bk<5U5+PSjIT*tmnez7rqjwUN^Fn6 zAFtL5?8~aLsa1vJMB(q>?iu$wWhlq!Je^IdW7?&h#4MeGQKfw2Nu3ers`mH|<$LbY zj)6Af?+S0T_JDO4cWzeHdTU^{ba>m~52`CZE9qB0O?Qk`)z<+!lO>vZExdi+UD`ig zsPl(6>Kvjk)ko*rz(PGW(|uK#SmYIIhQCQtZjTS~{~P>NHf)Q|{3uuD^Tnd{7KJ}tdD&VRyvAdsVz61T{g428Z3HkG~I7c6nh^sJY)KjM6^ zhwk30>yPW)s?LcW@oy8aiQ|^*1eSZ$+oglfEBQpb3&_Z zD_>`pwNXu1TzSln$vojaX{{}i=(|)aKSa8Fqt0)cplaP8l_$Ae(f1O6p>%C$>5|pb z16w4~ot6FTuWa8U@#8?|XD_M`iTdNUxMi z9=?D`UNW7w2ubJA1agnM&JoPwx zBRD=dM0Li`1fK}LA84ZUN6&Nn>g=*?ap}y&-HAIB52yoVo5b?Oi9{W*oqPaJXPd2x z=?~QRX1nk=Q91F~-1+W$o&2Ax`mLX(xzP8Um8WZ<4D?Cevq;^M65^8%vZbpuqkLr& zKh^zTYj?$I)ly-tXDGvVxopA@(i6%c$SYW{jLSQcloJlPXzg4ri!)P|_eW(7nn-Wn z<*bq|9;v+C)uQr1?Ev{jwsMXWRpr``(!7_ea=N!p`RnXIq8*;KI*BD=So-WnzG>IWJfQRPnD-#9xJq;`wM@m_oz54bd6N8MN5o7`jafL@a4uuye)ZB)fL zU;B+#h^yX`FIS;gLUQxE?DTTk-%I5A40RTY7k-kg{UIKmC7U%(bL^p2gr>sKXM%Tw z^zI~K`z=BLob)gm{0;Ii=)Mw{-7gS58p^&klt(~UB6@1mKgrh<=;(wWu~S-my?ljT z;^>{pS~WV9*Qln8t|oLviO8>DXH224)>)zA0qXL$>3Vz=zNN-awa3CKuM1?cn~RFs zdY_gR$K#=M&X0OgGx)6TX(`LuQubW+7t%|+bVJBeFcWGfe-pjG)z5jFMUh6y6=xikcA)0+5%JbFlB@egwGoobruvS( zJtM`R4Ml~9(h;q-!)8R%iWQ3!3gkDA60R3Xu7B08tzYH&Y>Uob@f->#L3N0eI~CXRhJNrTE$C;oQyKC~eU4XLBTrBbTLmi}*vsU9|0cT9!HLRKdXd8^ z04v(M_qUeRrXFc%cp$2GH#;tBd&J*Qc$7rlxl!Q5LS*joy(d7>?S;v0&?sM9?r zsD9HOInul*h1oUYO1OreO!N_NA$(q;>pl50;DyGHC5_~ zL1CDlOmwbN`I@lMLStkp3d+|vzGkU)Q+*2k=tNJivQj}XUo_Y%-rgWfHCQ9(%THe; z&9_4we~Z3rCE491_#@Kn%d}QQr?EQ~C)_1FI8-vzK;yU4Pk8dE=Jc$z{%6wUb2X!g zFmhb=%@+ug7FvI}P&nx&titIhb^RL6V5>N0twvrfDs2=@bfZF3H4wMN1TP(%hz=_S zHF(=BeBh_lYMtt^{-?4R45G2<*aUCK^(a$cGa=^l_rwQA^RC zzI0T;mL~7mo#YItR;#}sj?*Z&})iljh<15^`i3^@^Mtx(0gm2Mz`)! zrTUaAY5KMyRpojrow2B+KCWxi1YKAf2CkxVn*M#%D$^^BzHSAwzpP$Tb-iDFyjnEL z(LJZ-m0m4P(_Y^m)`-991>fcBq{z3lUvQ=&XXhFKO&6?KVJ`t%2y! zKs<6(_}DDDog*&5N>R&ApR*rz_da3Z0#PF%`>^o6Pgu;-^W*wSPraaI zjy(|>@+;^&w?VM(*PNgkUFAx3J+;`uBu;Df7d9&`Nv&VS1KTu9Dz1@9sa@Uv4R(m@RRQX5VEGd?0Yj%W)l%k@k$KVSfT&%D6#as33k z!-CWDIaM0LydrAX$+hTI%p{NC=g=LHJQE!vcWGvalK7yuo?ehK$tE@k3B{^Xoo}`B zbeV%D@Ev;;w4+(D13kU)fCH*S0s1ZiB^@N86*fW1^yHYCf(5&Rt*2Wc6arUdv-U~; z4ryMT7HV|_$OLu`O9<^4`>?Lxt+BU=JAaja-XuQVqEFFXz=Jms(;K~ytT&Ja#y{~i z0u=|yBwWD%@Gbi`pjt$q!VPdEbAqesHVA(eie~I`DNO!l+K=5F_#kM|h+sCI#!oyC zx(_0mV2k}D$Q`^$r@wvreXlT7q~G9x!XypxO2AH*_%Byb;|r(her9jG9gqX_WDIh+ zfcXZK*VzsSIs)!b((I__hXxF2Oge*tb6}E zLI+~ST1&&V){Cy3Ern64JD8ny9b^XyQU#{qC&LgsG*aJyck9SWmrOJSl`r5J|BO8- zdxaTfi#=xS&wy{xlkjdmy?7=yVQ^uk;DbU(b?0$Cm7N#p0Qy0azeFaG80-?7WXmMXH~_xp9;6?=NDoNx9np9JL51c;((xyd#AAA)Z{RBQ)FJ%^ z40uiGSu`>liQbyPLA8ug448lszT+ycVLuT+O*@eurszhJ#I z+4Te5Pz1jYosOiU2TZ@QH;8MgJ3{L*W9&L|tmBh3n(g!fR>Le_D0ZG+lKc;RTnEPB zGdwRK#^(pajA&Ab&lgML0qmqS_}(OJjDd}^dyEel8O_2AZ2}B!*|R<{Pu>(8jofh-8a+09|rg_ww8<$&2l?GHZt>BR-%DFS?v=s9=<5fFXLoqOHIi zGctP&4td*O=tX3em=*m4jf{2%8(Ni2lvy8s1D{wHvrT9yqZC^IsGzl8r_6$0t9U=q z5kJJy48R23gA5XbncfB$#9~N1JjgSd6FLi+;6AWq``3^#n>TZXqu?d93e;p=-so;H zj6Pt`;vT^c=auN`^oxbA#6baJh$r(*_Tcd>ATy0YH)kXWdLw&qDtyG;&>?1(42RGa zn*xroDd_a#8TyVOQ9<({c_Q{*eAw8*Q7KISS9m;r1P6m z5qp82F)jmZ(8zowFo6{Z&&-K8Q5W+x`l5Aq>4jH^yns)x05+%v$3h>XL~J>j$J-1i zEgE(h?!@ndzT5*;(8OdO_<1@Kie}<|EH%B#iA9VyNEA8>t!@^atH7#xDrhw1$SeYL zvp&>N8U0qK>*zL&ykK#&law|)ZT5sGnyf$*o`ZxKPoatM)6J&fUt@EbGad+js%b6g z0N3#}W@J(aZvahE@(ExQ${{Og0%9&WiFiFFf#8UH>2nMZ;h#2?MK93LJV^__7~05m zB=Qaf#TuV($mF$5dqY=z-;|^xoklIV8S3#rmJC?19b5|z;bW65IKjMb!@u<+1{YXH zv=4hb@fna|;uiA+peoNGT0}l98#iPG8emoM27Uer+gDc>A(`=@d%*RY=Pogc;BS4Oo zGk?Um3E!71*$-=SN9Stn9=JqgkriAASDF;1i{+-kH#h-ad~q;CR70#$q?d6L zk^r3C$Mek|68Rg)Bj0e3K?rYJ#tJ)##w3zsB=CuSh0bVR{66#za2ZVOohKeMD-ECE zxu6a46^P=X1bmEcWe+wqMRJe{^gNn%xBe$%XWlZF1pNqKh{MkWG^49#koB{#ccb`MV%{PB(1Ep&?6 z3v4wKfL{naw$~kLGcST!q4UTh7-irBvfiw65Cs`8K@;z z6Q!6`LklzooCI&81(=1=+Po|*9@2s3z#1AXc(C}t#D3KABlm^_cH={_U!)5y3u7Jv zT!e>Al|N9MUky#oBJ(XcEzvyiTF_U>xA7uAG?Ich51*pf@KMYcA!CAFHO~mm0Hzra z{!B>)_XvgyGp%>0aaw-Y2KIO?WEOwRqDtf*5S0E3rJx8#!R!MB>mB zImDBIv&=^TldO>$wva^Q3zL46V#|OTj?gO1K~?QZ3^Eq}37A8|Y;?2%)(MUSN2ZDS ztxQlLDP(oG>5Ux(x99{g0*9jUfCH-w1@H%mo}eZ#d<*kA&@>hWW52+UL2TL|*etUJ z)ZpT%o&ZLP>r6jGD|9fl+LO$pa?*s^F*0#H9qokwZvK&Z3fRNqB;M^*474>m!B$An zvaE_h39^|$XR-&ha4ndCzSsq@ho_1cze5z|Z#V-UG}$tH#FNn3Xh(7^_(Vu1S`L0P zjzq)Z^^pUFk5axa*f5SKx*$d}o@0I~YYe;={emGzwU`WRZazMmf+u3DIPn5cW}kkN zjY5{V1I~r7d7%yPWPlBftU#+GPcD{fp0h+yPTmXSoC084($%dLOJ*q zp0J-t4kPZ>=SV)f3E%L4_QI?MGRG{cG!LvAxxXB}(QM!tEifdQu+!UGagsrn_y#*0_KM` zLaLGcl#h>&CGTVQ)+}vUu)+sGfu?8f;MU-PqwpWhI|pVWS@W4v)*g=yy$p{)XE+$k zh<`_vhF6WX#q#qzaf3zU=oi!7e24ajHuy`H#o!Zg4b6}M^JDl4=D`K{?NFIc7SLboS}IwIwWsIcE?UP0y=1lgae=X_y#GIHcf`if(x*- zTk?a>14pKLfx>h@UIN^Q%?2j01cfaUH%$m7ZB4;w&sC-=_{}&5=u)wsc?lMknofl; z>~Fk2D9rQF)waUNc=(QZ5m-BZvpB-+p79cQ!da%vY_*U(QcrA@@hUi8qoB)S!U!2>ti!DEn!|EevHM{Df>?p zX;=o^DOs@S2nf(h;2jAz-`%Ln3O!tIx&^PniLNnAXR#*{AO1cv1-z!!86VCtF93~#h9l=^o(oXN9iJ z0SPou2YjTgGu(g=!Ai$YSwhPm5W8D!gHH?Hkt)*!8d5%+VZppo{7d-7^t^GK(b%jW z*v0Q9&t^F08uQ2CA6p$HJ~!_ZzTtS(& zQ5^omzd(+RW^g;wh214niG9b?Ge^@lz{za61A7gBV*xm$?$_k19)3F30ACp?C$ob+ z;|-3g*w~STuMG$%f~kGFsB~2$sRH!cQ>D$Z&;u!KN{x6ggqD zZ|F(5n=9cipu@%kAAAQ?hF{<^?a!T9TIPdCVRW!~-7u2M8zWQjIxnhDpp~t#TilC} zpRzILufhRv63>8(fggR0Z)$Wxukw6g!|Na;i5#GT!7;jvyO<+mnWjS~_=~&Yl$18- zIY^m(0=~@_vl@+c<~p;u_yD{ahq!_9krrS8@8+Kq3qCe{<7JcZ(-hpMX2QL-~)rsyk_Il zB0)-AWc+A+gEle@p|jv_<2-y9#xskM@;9L>G%=3>+N7kEQPBRT$5Xiu<3Ma0{v_H9 zO=x*8i-W-|bKyS5hC5TfjGahmoNZ4vIpFC~5nqWq7!X1o;kAlaUvL46^*+yIcB4U6~(H_VK8W9LggIi2$)*8H`A+cO=8_xo# zKnHj6hEuSA=7sQVWEToD8~YXxx6jaGU;@dq-wby~L!JsoQkXQJf~(AvM~gEHqy`

QQ*1)#u0K66`4jqBgWQIHNA%Mz8U@Y*3 ztnosE!6`peu-SSHbj8QydBALV!)`!Xv&rDZ@W^w_|1Zb!^s&Xi z;0P+=O%v}DBbo&^WJ$b@{JVOZ*Yu#XIMhF z7&h%rlLw@i7q~FHiZ^0<%QQcFH|61TkLghJ9E}Q4koofBf9Q@3nT8=gLjR<6GrA6$ z1wQnlVT$=14_V#-4*JQ*dWD}am@PxJ{k z8$2=&-&-UO77df|AitxJn3v%KDESMTGfpZdVO$_(B$HOOF0cSC+z)L{X7OXuJhnze zZp(D1c@uC8Fx%{bf$@NZTpC^sc`K;Q>Hu1ZxC#!1Lrk+X0us&4!JtLwSXT5O9B8>K zyc*U7p+5TDIKt)y1m>Bb@u)t)yWuJDCbQuga2OJgj|C3kT`VvZwix+;aR&Min0Ou2 z)o>LQG9LjfSY*WWp$gaW6q6;(Fax2*rG_&idGLt+v$z!Ag-5{}_&_GeWpLgv9y2wk ztXESBm6i0&Z0#T=6^GK6RRzOH5r1Kez%}FZ7jYHqid>7o2X#^! l+_arxDuq9I!fXi96`Wx!AIu3EX6D2Qj6wDzmF@8S{|8^g2o(ST literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts1a.raw b/codec2/branches/0.7/raw/hts1a.raw new file mode 100644 index 0000000000000000000000000000000000000000..7332f936e45ab42bafbbe8299b70192f5c4e1e6d GIT binary patch literal 48000 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�JRTnA`Bn|L$C!l! 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 QM}0wha--MCQZ!Zm4<#c(J^%m! literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts1a_g729a.raw b/codec2/branches/0.7/raw/hts1a_g729a.raw new file mode 100644 index 0000000000000000000000000000000000000000..130f1ddcb114f8bc4b2343345b2df197ffbc0be2 GIT binary patch literal 48000 zcma&O1(X!W8b4aqGPFKUd>$Cc*C87`+2PORf^N;-h_+y-LgPXyzDABow z!@xHhgh2u4?O`Pr90K~=GjIRfh#iLo&?LMV?iI)X6FnNlM8Nt#4-=4e?&E&EbiDg{ z0EfUqoHv4)sDLRB8?h26aggxfyMSmTDh>gQaRFKU89{o;{|kpgxC!_g#tt0B$7B1gVBTz$)pgJ=kaWw!*lW91x&@f6}$=EEyfLv4R+u!Bs(EBVKYM4gk&wC z{`W6PKKLf&5#mi~#)q`wE!O|No^dgQL);ad4{4nq)FmT`RYhBz&}kr>MfI6~Xs&S9bLAuSWMhR;QAY{k1AV)pmpO9fl z=LL@h&C$?6A(yvyJ2Y!8z`z>hfS`opv*4xtA4!GuArRz)pe>|_KJY~FMp)SY`uhUN zGGu%GfGy@{9JHbYj-n(fIM;=w3`KROmYrMp~7dj@an~+p2@Qw|R z6A!&g2-4yF4|YQSAqy__Dr8-SEd9W(5V|EGWb!l|0!m(x2EjcsyB)YwP-)=GeCV0b z^4y^0g)D`&7KhL;As+!n=&jIoAw5Bb&}T6VLRdrwEmxYF;5;O?-;$2t=VJF_wC1?T2|M?3N`yU*fL8!u-I!g>jAyu^_P{Z0q$kpGMbUMuEc zh!-I{D`GP-V}yl~AR{q9-1ruvJpgV+09Tn{b6NQK zkUc91N>T7lSnd#SLho;5R1=;`$Vx~}SR)sI1C34PPoS?Ez(!yg4owL~O@bQ&r;tSv zcL=)@32dyvSt0yRD5eR$3vc$;0t%le^d=N*7>EJIERVv7VUPp`)*_A<`XwTEG1o$# zixM%1gndcJ{K>`@LIV`w8;&Csk2r|XMmMCKga1Msg)WLiSU)S?<8h_n;@iki%=VD4 zkHIK{9x>m=EC}Hc((bphh`@$(p%+4PM1(AUci|=Q&B3RT#6Q=30WTBK zji8M;aQzO*^(F9###Qf<7Nj0DN$6A__#mRMkdF)leM0BM@n0ru_+PvuV2{F;qcQfM z{3+kY=kXQ1J@3x9f|gt!NrvG#P148+Tz8U80~hk3(R2ACzK{>$zw(>>8h^-RF`k>( z1ayK|IdCu@{>m4$6}NE3>!64Ff&2(qmB@Z_15{7KbuYo!y}TBWr{i^@Iuev`cFw=

uZh0Y%DoKM@w6zY^kgK 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 <3 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%0DbVl1`(2x@^x1 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 mDH}Id?)d*}fn3{r>@Q>`+1g literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts1a_melp.raw b/codec2/branches/0.7/raw/hts1a_melp.raw new file mode 100644 index 0000000000000000000000000000000000000000..a4040d2978388c0b14b7dd2d187356ef85e1e378 GIT binary patch literal 47880 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts1a_speex_8k.raw b/codec2/branches/0.7/raw/hts1a_speex_8k.raw new file mode 100644 index 0000000000000000000000000000000000000000..9289e1c9232c5e91e47f8cd129ac64709726bcf4 GIT binary patch literal 47956 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 z�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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a.raw b/codec2/branches/0.7/raw/hts2a.raw new file mode 100644 index 0000000000000000000000000000000000000000..6d9cf17bb9dc1caab80f7f12283be5f638cf571a GIT binary patch literal 48000 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 z�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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a_ambe2000.raw b/codec2/branches/0.7/raw/hts2a_ambe2000.raw new file mode 100644 index 0000000000000000000000000000000000000000..7225f60a964f04e73ac381e22b343e51987f86ae GIT binary patch literal 48000 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 CQrX7< literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a_g729a.raw b/codec2/branches/0.7/raw/hts2a_g729a.raw new file mode 100644 index 0000000000000000000000000000000000000000..9199b0ad703803059948802ac59ec39e859f97b6 GIT binary patch literal 48000 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

p_Mt2C~rTxyq@RZL^-jVpwlkE}h zwWVqNhsZ>9#;`>y}x^Y9;+B{UYZ$n>+5=PC1H6 zD-rqGFSb6M5xkWDroSPoRIiH8(o1uTq;igJ?rPq�ClX-9ubg6;)`<6*62JujWU; zh<&Km1U-h#5V(tz)x|u?#xB;7&0@T?0`WHoo#h;dVe9!wN)^gkqPi?HIw<&4{muQq z2H%R7)jM$|^W26_cauBG z6_EcE6t0!N8&!^sNLtLHR@QEycDobzz&JjY>tqhG)|$(82lpQ2xin>{JVKu7IIG-{ zSII5;qgGX8WUNc{Y4C^O>`>v*=cr75%luOqugrJI?ouAfyVbqWnPX3vCLrQqvtCUd z5!)Z#5KU0;qZiZ=_BP)d(XKUwDv0NtWn~(lvMb>Dr}+-bMX84Tz_v_UE9MBrtwrXq z+Q8VrXmYrEq#E)97V6X4Rc?x`*jGC`xZZMQBlfqi?PGbWa2VdxsruLIYpOqXEY@24 zPyfOg!anDA^1ER%y9qAX3wPZt^Nx8J5qs^qZt?}*DPC4mgmpq~kvdE-Gx}<#dLYWH zeblU2M{_5u%{`IM$q9&4_}%`S{abrm-5n?rhsFbu;`zKc1Sc>mYM4i_| zd~v0)bYH1%|5%x+OhD##2jMX!>@{Y2^KI0c4I*2quF=bUVwQroQ3YPc;piu|oxco? z^#P;$7?sR>+*kZ!iyUsmkG z7e@E3C%l4a0Sy(S8bD^Rz)Z7(^*U;V9);Gzp(~M#U&j{{Ci5rwN6;M*6UyqaN#!p z+F7-8v}5#k>_&9H`h}5YzQ!FA`pTV^iZ;>l%obJ}+ipsQ#AZSEyMHS$7Ag=fpqHqsD*7d=|^RS8loX$QyQ#Xbb;MfMvq z2EPHP>4ZJ$;QD#kBWX@iNSRIW$$OA3Ib;q}otXeMucMGZ`{Ud7xk;#ivKp3zhNze4 zfUedWG3ehwa#@cZ-9Y!L*SY1;b4YWW12|Mg*6Ciz!M|dC`H&{7!S0@h^@SkwHO0sk zAZ?z&Tt2*-0_mzUDjn`ee9jZhSPfFEAG0;YzE#BXo&wg}K+|83Z#;rDI1}Bzz6X{Z zcrMBH!`i6c5mm_<2@8V^$?bQ<_}0cQz6Zw2A|tmjaMlt#dJk*Ag}HiiTcI1M*zHM3 zWy_(x{D`V31}ZLX=N99g*SHku*rm7*)=EIII$kZ0jMQ(S5B!IWR?6-^%oWA=XG3Nj zg=!CFxyk$-HVu_t*TJ)15pnbvQTJn!brzKj3nA;h7$Cipb0SA}1UC%5wXVS0aH=3L zwHc_U0_sAR1zs0JD|iQ5)lyhmW+LZvDsn{|aUVj`{v2`FcD$2>{oVw=8bYdX@xZky|p69H9d=po%{J(gR?TSph4> zUTEb5K}YW)&g?hH&il|utculv{}9%n+Wc17V_#SExnj3&s;Z^sxnn!j!S$t~wUXSulZZs2@10Co{;V!uGHL8Urc-S((7Tp)kmq|Cxw^)*VL`xP=abFm7rJCj?tGzHA-7+uY+_i^oa1mdE{b02fs)NIS z%vVEfeSc_3Be`zuBmQe{G5ZzgYAdL553sQX)oKPp4*VTFx-09=cj1|w_rz7t5Ci@6E z-6xPOzJ)7RFVg$- zK4fbT=kJ?4`SRRh_7ix@%7Quql^~y2=8Kta`3Br2_BS#NI)LMxv_1jnqdK_rQKjJ% zt0&*vDr}w?leiqcfm|H>6?hbh9j~B$u@&2|G=b*`zbb#N00w zvj&3(ei7;zeyg9TnbWOdSjSy!Ik;A7RJUvl2sX01u{Od@+{k12Y33QuDZqx!Hx_Oh z>0GMtCd2R{@Rr$<`<$=B>Y>urC1hE-;Vo<|4&qv>6>MF(_tgv~ zWVU3B#j-{zLF1Mfe+wel(3~&!wek&9^dqXGj$jv;8}Fg|&vjOb>tL=Fx``9j(dfo= zRc$K#%|Fz<(ok-Jkt8i=g%B&7V5Z7P(DB8CjvHz0mX#>JW|cJuN_I91H}0aV?D(;wI#AWeW$* zLOc%(P;1oO5>Qk8HGQM>*y?Chlm0L(hyz*BxM!ac{er8Y{1`ndH)NB|U*$eg&USm|8Q#H(5@dAgBfbrl=wSLLAI)N1OM9OhNSW51^!=2d>3 zdeHW{aYMW4sH&~Co=c~+47r=po0YWRh$M=4g(4SH!f~s+QCw_~xb$_xIdiPgj611+p^QdV znp*OC{UV|~XKKI89=?=1SQ^51FgHJueIR~~({Wq+ULVd+;p(!3;t6dN_mezCeIy*` zo9HcVy|lgDN_+L-56UvZ9u3+nXpFlkH4iU#wq?Cz&7Hq%3D#{yqglcf%gfq`TiNH# z6z+q2Y!ZgDomLkA85hQBY|DShE<867yGxYa7ueNf$t93Wtb)1cr7yd(SvsC#Pt*kY|maU#<*W}lY&8WW` zHf~Ed%$xcq`2nhJrNdXYT;jC7LTgdbsz?p^J;wX|Ue=y}hHP%1aF-2WA4o~sGyY4d zaj1+7IcniPo@e3n!hLa0q^|o)G{pZQj|?4ljnvYNuN>jXJ2KDR)<3p2Qc>4V{#Pr; zeXE>TFB|7vJt8+)Ip^5W2TB*-AN|qUUcJvkwhht#;%0sw_CCuDTBU_@$Z)9$E};r% z5RHEyz6hZefr}R>P2ld=?)HSvY>qvC9{V(>TRzW$g z_7M9?gMu|(orHhGzuU{2AF*pvu6l%@CuZwCxW_^YIF<*`e?d~}ixZh{bu=}hy0x3> z{12=?*O;%0IGrf!#z<5{`#3tfgO$Aw=dSSxeemQs9;;ll?!J&?sFHT(`-FV z&RQUsi_OQ(j#v|^6!J97$-hJ&NoC|K;p0k-yQ?)*?r88R%0}cRavbuaXXOf91w)jp z8K|x=tIm|wprdDJ0|7|w_?*3 zA5--Q@(F#X^-!FvU*J3O!_8vC8tXKypmydFTcXo+A<3m0azDOI>;p$sFRQ)n92T3U z*L7c14;i!VsXB5WgyiTPTS>teUT5pbJGI$z7k1HTDepHYns-6xiy>uIg3oiRd7LkW zxSh|$J;)cDC6}@!qs9Becd-{5rhZ+SVlOgkkZ0}|)(6gp)sR~lJ^v@5~{ z;fk@&`dUabllkG|S#1z+i5HP)^f`Z@o6P1}k5RwoGGydS@Dy}36Hw1gH%bT$8Olqg z)7&8KvUGx9fDS(C<{kbmu0Qy|Zf+htlf^7AY&*Z0PCmeGXa68VnDN_%KKcj3O`)Z} zS!l$1vDtyYas~gq%-PRs6UAkqIWaS}gHHA%k61&SEM0KAA-1o*Af#=WYtMD8% zn+TOriTrhBs?4)SAs74$Yd60ZUguBwGsb+u!_PO9g=xqLM0Fr`9MucQe5 z=mhHY+_qBqbL+QBiCsYikuj zZ?6paBUi8mLTkuRHHEFX*^hJc**bU=AF{Q`ef-=igYLp>tdhbu2M$2j?}Mz@^LQq&-|Nt+A43bj3jJ*=#-aWTIT*h)d`c$v z*$F`YqL@4Pd;@un9DVZ|64j>Oxpw1hWdzXD>o~X^l+O zCK%JgcdkM6E(E^^^#i_w{Rq&X)3CY-c5Y#pEdVX@-<811uEMKR37Qi15axmT2l&<` z*cURkGnA-5`o`^degoO zKg(;-$1?ET7w}2Le)a%595h<0M4yf^Bbc2*Q)KYRl!2_C02phCjA(}$iemN%=;xr&4IfsY42_pOy|j-!e4_^Ri>k1HWWs`zjvZ{n ztVytkCt>D9z>MKUkq5N`cJT%vQW5LR!>-OiXS@qoC*iDBgH3|R{_=sT`><2d>TOsR zb$8~0H>!P4bU~gx7v?Hl5KZwK&PYB!qk(QpLo=oR$zISBRlYriwLgLP`y8w)SMdL* z7_kU+p&FRU1zJnOD0!HVJhaqF`8pm3K9>sI7RRR=fCnUiLMRVg#w`8<&;MSG_!JbH z2$~!M`mBMSQ#S(}e3R7?>re)B5at;C_s0N12{8N%dwmFc%D_s~0EI-rUjP#wdrAQ401H@@7gn8Mlx{e-Aq=f@-lAphSHWqQFyQP;M@E_y}}j0)oe}ehX_S zZ)^f!TnOV)uLznUA5^QsGZ_KC@?Zxcuc-r%RD6nRJX3{j@_N_6_jJ5Zu;nl}K`Vsy zmIqX+_Opr+GJxL<#QA5o=Tc z|9kjm4j_|^RTss3)W4z%=Achg*KvwtppM@md_RI!QYG&wc0|>;qPaqr&y;Gc%g1NFEBUJ zL#&{NLA*9N^?fJ2Q^jhEy@>b!CVC=@&_Gp$MFl5_!!vrSV9nHz{2Wf(1FSg_`xJqP zHwrjP3|R8v5yH-M@NPWLz=jpayJ=9gM-fmk!6qH}pcn^=zj%aCQf!C^uTwSkV%Wo5 zxKkaV%_X42+kkTotdr^;zKwgOJL)9N<5h*yU#E&(wva3Qlr)oN20pO_3fN?n6556dB>bYn}pLkpjx9j&VG= zndyAr0o`2#RS=};l+Z0foSRmxV7Js2g}SQvfDaqsOjX{KLGkhE65`Y)L|hXMFzV*MGIs|0RBirjG(tb{7V6VIV&5UMjmQA$Ju)M+3HijfO2MxEV# z1>Bx$%2xoVtOeW^1@$Ii9Vz&R0V;V3c#sqjE?5J7*90v^F-|t%M|}$zPAt*91HY-D z=*k$w4Vold`^|z%@R`62#l$?rBNwyM-NS<(i00gwDHXVl$1qV}pyK$8df8B&_8@lm zxL_wQvDN@+n|L!tsZb4f8iD@$e;>pX>9y2?QK>RL)y)@i+NnqVOFWacns!8cp^ENF zn6q#JW<-og&?YSB0rs?GsvJ+99H_?=ot*&oO+9R4c$cD?5(~}^RWc#m(0&R75B36> z$1ny_RRo`w@G7l@IEsjGCE~j><|F(PHi-Msnuw+-=E#YeDH?}jzhao3B8#5knIg~V z6h^W7L_mtDhGc>?&_FRfy9)R+(J#?eY2c&;-k}&FKj?y@zNjk&#S0N;>At3$o?@J+ z7eRcs`0GSvFEOVd^iC8~1v}+%i`>V(LH;j_H6njUF4mNZy;J|F#<-mdVbxjKH}&VT zW7pJ0C#L|9#37ULxf=M@LH%d&cmz1oiLHfIx=;i3I?gG@|1|`UuUv3auHinqfD!DF zoH}BTRGgl3kRYyr_Ne1QFML;njIa|vn@50i6^uqQ;&puQD4xTR6xx8JzKxZfMik>B zL`~knp6Y=MRRUxl;x66`4@^Gp(bkB#X^Z>C0WNe0@JhludO#9v4y?Y!DyWu@4cwpUxPpEPk8WrkTN^Kuk;%D)Okor>+pLE=ap`};(*5k%y9xT2uT*Sv-qpo7>%T| zk_Ehj`e`6$r$EAC7_TKpY=rlsfHrlt2w;76AW=~luzQeH{=}LeW50C%i{Z7GnDIJz zf`QLf0}LvIvZKHgRi?4yQ*{bvrEY0|<8cevDT$rdEuan!@XZ5u3Sq4BfN%uwA1d&> z-NCDLmr++GlHKSQpnHxY4oQYe$J!p_H5m{pfxWs5_|F5pPSOh9w{HNOg+Mue?9~L# zQrvQ7oH?Zc#{XibOstvwN5oNIfKswRTS*wdGS)`2WfrKA;tikS4CI6I>0Ty2MmIW1 z!WA&H18boOxySf4-BBcw&?zDLmSR!M;%q9w4#jIqn8}V48;{(hTl^(HPq!ph8S;Um z>4qbzISF&nX_l~lR=`&hF(<{{kxWLEPh6Hbj)D`NR`6bG!Mh}RQq*P`4}u!qh9sew zpdaG0&i@&c;wsS+2{#vY9?8OkV*98&l@oZN$WA)p37~_@z(E_;>()kV+aGX~$n;Pb%$We-5q+6OK&Md4Zw*W>Y&r)S2f@m`ENAaJ;Q8c`t zjn5IUj6zQ!X{s2WDXNs>BI&Lm7{qxat(`b)0N){QA1K%ZhQ+wlABLg@i9^PDGp(DX z3(_3iSWyt4Cndsah@LzJyCyl1x)VLa$-7rTGjx-O3wD-*lSG)M8^wkP-Bu`aSwKB@{7rWg z-A;7tCl^4$jhTx8Pl$#r_*M$u6LGe9;Edz|ig+bHcLluiKg@Us_XkNu4BXL+6_G^j z_#X&S8i9*j!bZ(0F<2s=)|oFZyTvI!U5Ky+r~)I_~r=pLhclREGifEV4a zB*_r1(-|b1AWe~e;&KG(8?;lxND3YVNg9cCA;K?FfBb%?TahFeqGuasA)XNXADm}m zPZXC-kR*vu1YY7jbO@f*&4%P`iWQFH5i3{&$>k)05DmnszydXs4oUJdy+=1Nn#mW; zMN$Jv`1CsU7^3)QI%}j&(|8=dNfbo)t&UaDO6WX>3*I9r#c@VjGsy&nvCBBOBaTaQ z0gaW5(NxSpE27A5l6eWYWHTViisp_#h}sDvB(ac8M(@NU*a<>$2`1hph@=amy*L-8 zZcKy;!U#za|5tuf3wA>h+r+<#gPY(VBxMmaD}e)+1y`UBLS(U_K1rk#(%B$+gL(y# zMov5`9v@FVEh}Naq$@fLs3HuQ(5a@AK@#38PDv+@q%^{gf%yq)26jsnM6^in(tScP zjJMbY52Lt4KJt04)O9&zcO=*tT#B5q74k>pL{k1ugX z=yW{78IEg=#JS`Ai=;K;6mgpa@d1J>X$~}ZoWBzfr^hRbiqj0e8($qsyL2*%8&E7h zX)kog6bD?(6mUP%e5o(}6WF+};AW4XRyx5X%@GWUD&rJFCxuWoh*Kz?aatFRMCU6$HmwuO_@5ur0LcCm&pseJpo|8>IN6_w z7USHTxJ8_<*oy28d{nDre zT{;W#vlTyQbn?hfNEVJFn1v)f4e%tG5>!ccAU;e~L^K~iE3Y^z?VlhXza6kW{LttG zL3+gJp!^@=rbO*T)%1wNfM_)Sh@T6}dWq-k(0!+a50SJ$HzeVP_8Pw(Nirc^(&H6x ze>D=}HO^6J_V_yDnkl_XCx_%8qPqAfw98jGq%5I0rIQRuC!2I)vhC5?ptD0OiNpNW zyhNo$k@P)UGf_0%D)d8G|6kq~hev$>@tx2&>Bh(}_y$oAap^cOq#eiiLFYgIAnP|h zXyqzaNEAiy*s;_9cU-f8B55@=OZ?6zT8xiNJowcbUO|y?LfkI?6PJDI71~pL9D425 z4?&T5A^mXwv(h-kiQ0+p5J#lX({Fs;H2SL%sNdo%YM}qcf8wip^%vbl^g}jm!aO}* zo#R)3)6VFJ_!Gg8c15rtdX4i~;%sEaAS$Nrk0gmu*F2(txV#eQmaixxK2IEKuc$08 zDUjWsU{CMS93tp}P9lvT=SOk+kgx`l3F$#QkJAc$i(pMSC#oaqg>Fnbmvk?YERYODjULBo{5-`efG|jWB~Bw0pZaR_S91_H;A%lzNhiO%C#p%YA}j(R%M z93*GQIUD^=Hx=>0S39IWj<4`Z+=gKJ|Mx?yr}s#*rBBA;_6kcxEAbOav(iZ+e8um( zxMUgscARqJr!2m=I8BmdLwcMa>m?pUXP0P$XpEp4w-FOH(_f@_lNMM6ayek=W7IuxP|F|@0Iw8iDwDMDT2<(E2)@H7;z2SOB`QuDL3VR zD24taPWmcujxb1kn{E-(?#cc}dMwGpL>qBSydQs2A86Wr{LZ3#(OJN~$sS2MFxk?G zi<9n69;Nt=MR=yW=G7y9LlV~i?+#z>gZ4()il5Us)y2=)tJ4~%$N%L{@x9P~NuQ;& z7~j$V9i6NLacU<2O8h}H(XFZDm(CfjAP!l=Hen{ttq7BG9vJ85uV#J)WtyL$8RznG nd5LC-p9rE7+BtDddJwjW663Nn%@;ozv~GmUVI~exr4j!>GvC%p literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a_gsm13k.raw b/codec2/branches/0.7/raw/hts2a_gsm13k.raw new file mode 100644 index 0000000000000000000000000000000000000000..f0a58505d16d25d56f1d0c34339da4a0b969acd6 GIT binary patch literal 48000 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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a_melp.raw b/codec2/branches/0.7/raw/hts2a_melp.raw new file mode 100644 index 0000000000000000000000000000000000000000..5138e494a2644392e4fb5967276de96ede8377b1 GIT binary patch literal 47880 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 z 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�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 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/hts2a_speex_8k.raw b/codec2/branches/0.7/raw/hts2a_speex_8k.raw new file mode 100644 index 0000000000000000000000000000000000000000..c421bb4e7d5e6a99299c4cd97cce809972b9204f GIT binary patch literal 47780 zcmYIw1(+1a^LF>ltlRAw$Kmeot|4fE5G)XaLx2Pep5PuJ!6CQ@0t5)|1eXxpo#T8@ z*Jq~td;9M9e?I0}Zg;1ryQ;dXy85l^Wjw^gc&S|Hl*mNEB@xaEVR%XSBohPvHxOgq zCvjIIgoL?)4{EvFUa}eX_{O`)ADvWV-v=s6Z9LnHPNJzXFGhxI?Vl*527h}ty zBcH|){)(9pvJrO`JSpZZmuK-bo{CpG-h1(#my zP#$$+T%iR*Kg3)JnFMh!j22;xW5D-9bFBDZNHkwhg%0>IhR_Zndojl*%&TZ?AR5LD z=Jg^pgycQz02eWN5{m>!LNkQrc_EQ}S*YkG-?r@FOVAR^;~^WflL>yZz>lyb!Hcko zeBBlr;>8`ovyiCzKW)#KoUqV*Swb|JA;GJVn+23c;Sw_#jrUg2PX0%a&p|fF(A$*0P zTX+p&$wK#q*Af~of^r9BC*&vWH3FZ7_UC)& zd@2P8!h`19zVKs07Q)ZxkC>Kc0UnI)#dyN{1+{pCCj_lxJrG_)XsehtF{01{;je_J zGvN+}q=Jx5zC^@$f<6f|CVCW-$zMV9V+2l z|FtQ94HQWd(J@-ts+7zNHAS6vn6l=s~_Vi}&F?trUMnD`8dnE10mW{Bl1v7Ho`{=+t2q`VyzK=&y2ewqR7|VK;HPmw#9gYOR*A*7Gm9z z@mI{93VH?K!W!~Dj_5ak1&|>x;j8jjOrbr(&qw7+M65zW%NU;aq7UJ-vj1nrg7Zvh zs`x8xU08U&w1uAJ`x1iL6Z0>q$+vUCqwsTL{sl$(Iw>sAg4M1FDNV|fGNdTpNBvI@ z96bxqoQ#=H!kQ*lwO}5XV(k*%K}bgQO7r5ZAnps_A}mPQsaT@~&G`|M&|)!KzP;G< zEJn<-umvG`;WP84By3D*q>x4-c%L|EMl7fjo?Q5Q;a>#rY5WuXPy)tD1&zu0lm@L7 zcf=Z+@8R;J!Ti`ncoY#W2oEf5P|T?4FW-NQ5%YT&E6ykMo17OjWT01}?ILanf&<~D zgr*h&ZAD2*TvbSQ$gToD6~}7r29?4V{g77zf5YGM=lmgmjQ?NoXZ!)pFHt;T}v*r1B;SWU&A}rkr+ZR%Iz&3>R#5i_vk?&iD<%tzFe~lE@CTt-; zqRL+h#44JvL-{k3uf;+qMWiZZAXb%pOAy{tSRT*oLui}uiGpTfi=rQ~)`%F|2099m zV&K0#q)?aCBeh5+QUVgP!w2L*g75h&@cxuPf(#x*25%sPPdqWtd*p&n;fKuNF^&|5 z{L16$(vYnK--_78iF-nq#cJw-?1c1k!KLu?!kda1Q|OME*AVVx7lRQ>Ld#2%QkbnG7*j}9__TCT`Vq7yVb%qwfjr9*5tM3`Z@}FvJSlV~3*!lH+~7vEjD=)GL}bgOFAOOrg7Xh~*LysZ1df8-0A6Jxs1@Ev z_~HoYx|s8Py%ahse7x{Q&O9p+y9&`ttZhOYMAR?n$pRONdHp8hT{bw#--F~w6vD%a z{lNc8DFw1j;_vd>r{Za`QaeC#Nm7wiBjvztBzhKcq=+-cJig7FvlNVziFawZBcV^R z)<%QdILI>=G+OiIRS-QD%9B|^$V03wB3==@6tNc&v2tRbWjumSyaW|uUWGN}d&K{< zNQHjuxMwXV1Y|3bZtcK82nN z4U5MW4LXG965iH=*7@8C|B;9>UglBr0q;}rO*&@CgP9Q#hlqhiWFhpu1jefX8I=Iv zVg(br%0R#HexbazMdRX5RGtJ%=Cv}AVBQR+Lh5h%YgmM^hKCsM1;!GqR4gP`5f)Gx zl*WR_Y)JhDXnKa%JG6g;5yZ+>kW_`G)d1IJU@L_|msl~QKvxk+z<|3kdD1C~z6#}i zV+M5@81p}Vkssi{^WXRgTx0o2yf*VQkdy+xnvv;bHd#n^k=5i^y#EH2)F5Ag&o9Ui zWI4WHPv()I$QaTH`nHdM%_%?1#lg=?n=R<@I=gJ!bpaR(62hWDY)t zUx0i^;eG}&(7PDNN*3@WHkuV;3Fy5BdN0in^Ri?E$t4Zw*Yqd!JrUPPI)M(QJ!pBV zlhb4xsZH+lsi57%&a*viDci`NvvPbcbma@On`99?eTP1plYe*{{)kOr9at;Ym+fF- z)}LSHc-va3z!yMEhFZqu=f?s66uz745JH`C08D9)9Tbv9dJID)SqP1yfIvgBKr9acr zv?r|z`J5+HFrSY=Z!;bX>Aq)gScnzjo%u>=hYLFJ4e3r=K%<^POSE+I^HIDpkK{T_V_D428{zYx zkWmrRp7ek|wSw)W@soT3AHdszme#yGp9I}G1zne+)osW?vWy(UOnV@$cv^;5#Qzks zJ%l-^4-MLbIc>~c7$M9k7xYc$J7HNi@K>8O#Ht(te|nei<-b6BL--)*`p#F}wn=2{{boOZnf>)l68vf*!<*`vRk`f^_=v_Ixm3&$saVJOch_Ao`w5 zwviJgOsrsO*fnG{fh7 zTJ(~qh_yCVn1)ioJ>}e3Foq_%jkfCHM{6Z(lwkmv$h_-g}o4gP?z&G)` z(9n07JuS~){|5dhk>l_{glvM1KZK=Jf}bb}c{=zFJ`7qmja()|;C@5p;z19JF`bl@LZHOzlK%)wUhbd+o& zfAJa6oDI;;S@adnrb%QZJxF(uIpjysT?TEN@ND*ooq+z=<>Mjk1JLCJQk;GwGvPhn zupaD#Zqe)NyR^63N4*hzLuVq>ee_FduT)6>PF^8Tl0(uz(k5vM9SR@(BRi{)&{MS+ z+IMqv+-{7pdtCe7Pa-?I|8`BbXPU|w`qIUEvv3iAJKq}LGvDdp1O2>I z*|gi%#p!jvw->gIme*kaE?hbOZOlEV zYU)VCp@!bq8AsFpOuOT8=8jYiirYCZ_Hz90LeJvnxhI-;hdr4W5+=VOPg9;mztG;d z%$OWLZz>u)v&6@8zg5^=mJ}}$TiP1U_T>0erX&=4*WevXERp$3FwXEpbWYKQr5lv1 zS?Y3u2DTER!Ks-q58tcv@9n#d9&dVAEvqwETt|w2Q*lns%{2#B%`APmfYHo@MN%)l zEA#4~rw3kaNqXX4A@z-(S|+OM&FY7%6)LklqP#XP)%g6;je8dc-JEc9@}p9zQQ9&y zi``#wdCl>)w%0yfHKo|qh|~OH)}IOCCkyY-dD`e*qx3<%LTvkzlghWL-Mr?$lBHt{ zC}lm0l9y0-HD>T4Th)ty)IvmzaAN5XT`EieDL7xA#% z+xm%vv+lVX6)_g=P;)}PjM9UOZ*#N`C4TzuuInf?mFd~i*Tu({Z&|BX z{Ta18l)qK5zvWHfkf;8$0XOGA|1Kf!W5tkM^ih$hq6JzNuX#8=sn{0MEz|Q%y7A`D zcjtb+@#0>t$v=ZgXeggVggy{)#AJ% zM6F?U$JaklvrNgBk-N3ap2GLPx;o*}j^|H45_xgqO9jr>*x2Cvf)xuLh%u|z6F$8D z^XZ2x-`?H-deVz$87qwooM+0FuQ|5noI2afWfa(MDed3sj)dQg^Mb zDz^Q+ezASUK9owM<+36_^5-S4@4q_X>38>5zxhU+$Q#6cRla9gTJv$474Zk%tJTcZ zGmmb)ALEfPQn@BIY-z>!l_H@gUSG=AXLYZazeyiXxV8V4J8&{wJ+?vl zk>xUK9;-aH_`Rt9tVmLWHxIIRClySOEw;um&`_Y+_pzfaFUxT{#=AXt$j6MwCvTQ{ zOdqD*znde4$I7pZ)-3a1m4s^j%FiwGwIwR>%e%rERxf!s+OCV%&kLSF7|D?bNXW+QMtNb9QRpDmEr`-I_ zrL_NM?psO(y=x>TrQ~TH&(PeohHYV^SrNf(kZ`Zx=`f6!XWAC^ABGCIcRMO*1!?=Db!~+#R||GAoz}OqmAP*|&3(5x;jeeT zclABr`v!%-GFFUfSn%uk*rGcNIF$)nl%c(^W6nNDQC?PU9rw!qkGv%IOIs~{BflSL zmGa`lti*-y*M69l8kci1T!r3or4=|5D;EkEm|^@u?;>{%Rn5I;elOY8?$Q0-JLSyS zkB-6mC8DtDZ!XzE4U^ES=Ra&>&df^0}**b8uXrs6yuL zww?A(l*%6adg-0iJL;4npqSh>i9!F9?aHF*XHz;SzDjJ6@zpQuYb^6-WCMiun`QK)w z9`XE{)|1$km2_OR!&zTm=(^yjZaiw69$Va+X1!aur}en8MwE{j!j)M2?B>a7$zzjh zz4;;GkBmvlYXakp2bk0KB)Ya#%>GAYVdF|uMC{Mb9?H@9ShtC!M$R_1@gF1a{lS!; z=||IVf7tnPTjtD^C0Q*E_jIQz97B{`LxmW{TvYBKy*461OU4$6-Ng$=+;x2NZ{Ty( zOQ|vGe`Rh>xcAYL6PX^H*~R#XM=FWYZw+5aIgxA4w@GB=wTMyDH&IIq)TS>T!yElpjWAyDv!{qiAeXHp`yl zTcpx#En2 z3_R(3~Aoe(i-2mqzzfO(9l9cdS(;?RZVztkR8E;Cno+&WN zalp8`fY%z(8@W45?|lvAmEI94L%r?N*S?>TVa)hC`BA7ln;IHv*=C6+BV4E4?~M~( zOA2^xU)kEnJuKX6S*MEAHv^@P@T3k-7RziOz4Y92^ zHMA~_tl;$78b!8@nr!{q)zTf1cAD0iZ-i=Szl6TdsFPVF{cxg|ygL16`mmhUs+rA@ z2U?TNA8c#gy-_Ge^n$jC|wCRIskn^rl~=zSCZ zmXB2mSPq*P+c!mwakg{@BHKl-w(W@MVjrngH#?-2S{?OHZo%x-^wgAH$(xe9q@B(5 z=iUyVxY5?kW=1Ibyh@L_}9>E#m}ZQ!-2YJ-9lTWH(Jeo;odM zXUe3EFj#-OzR0lLFKA6pDhUe=MUs& zWZdAtl1jNh```YWh&2sJb{kFi#>=Q=7o4%q{a88&8FZ5?N-Zt%(D>E~=@ctzl8 z?vAY5nU6gCG74lr^L`(Cr0J5!Xt6Z5jdK)tG`A0NT(ixw+_mg7{;EXE|MF>iAXGV! z;w_LfAUifYKIb>@p1>vb5vwMjH|82MEmdvFmX=nFb-THW>9KLH@2hV zk>BC_(d+hA^uGyA2oKXkyrDG1aL-V{xY^Xf^s{lbv9F<^VV}}mZYkfTN68KTQ9rG< zRP~T4d?lC|SROK~g|y=2gw#Z;Vq9Q+CU-z8=?7_zG*6l+MPpCI$*=rdHjVl9MC}jt zFV&=t4;R&!0Bd+gexVkrgmhD`D%YmXvf(hRJx zUKg0hM1EfXotxzTK#6{#X5we#fe-Z{pV&gufgWeu_&%VcHolP;r&oAa zejdBrqU2lb*hi8nz;_0tbtGE%eGmL+EZGZ8?k=ARMDq#%MAFC$K9koW1Beso z%^zeoU%^|FzG(ZB?*uxqj^73X(id}eofie-a+@FL4S*=L23H}xdj(t}n|A|$t9Ue! zgCBsmjw9{y{v7a7fqZ@m3YzimkjQB4-s_XE$SI&R9bic%uoF*%#l1)02H*fG_)8%5 zbnYN;c?F;+pLh*eg_XQPFVBH3O(Ce}`2P{G(RaY@L|w)!&}9NH6odXm9Ze!Q zOa*r#;JPBu=m2Ww0%j76UPTo^1kmu{-6M6UgVQSX4ea82~0Q@?>!hX1e+Det_O70!Mj}ib)aVp`i{W- zMMJUzowwj6aw{>geifLF$XW=@{ROU9!1YD_O*XK6k>wOQT#;wWucXM&Qj5Hq6+MdT zo=A)!DicJFfFJUIfcbxl9E754Zd>W|MOYS5dv@Q(_leim_EQ47y;FAi8o#N+lUu3RYkdCA!^wbIM zVUVWCLJ71{VEuqNF8~7g3|co4l1L*D$vYt9nbakH3sgCUA7cM#TUbZK3V8sl1=RJGCTpkR zy<*8QeF(24ccCipD(z5u(PBX5mSL@_u1C@Dq-p#I=(<&+@bY)q1JaQ%U?Z`P?Bh%I z8hn)0f*jNbkXBL}?*YGmk4_|CK>`a&6g;I&p2DBC$I9|ISJ`%b481MI0cmVSh+s0$Ymxe3S z4BkbZ71|MK=(G7NhT4Zes7cys*=d|@Xl`0ABBzbaAcKeWGTSqI-ZH6XVMQ@q3q6yjW zFMa$zNy%WrTxFs&Gx}ic+_*B)R+rWIK|3G(%G=(%J#ZoXg7s0hnV;G+t-l+8CM&~j zeT6fcW)%qpcu(t+sO52U;t#}jcW#$kh0dovcwP9#vFGg7t;8$dWy*xe_`>r`o-46C z{&)8m)`9F;_U82N=|83|$xcyQ(l_RGr`>(teczrW_t)zB=6c$u&CFPz`z@{GnuW0c zeu+Wxvb&RP%{}z-z~j32Dm*Ooa$L&6&@0oz_&p^qm3mq-EB=;?$l0L{*%Lhev>Tok z-plGbWu#4VE^?KK*lsVbR98FZ98S@b#-!BG-WLoh4Pplu8&YO*nRkWXyKhR@GCw60 zd$s?`_LqG=-OlbnT3H*%7~&ts?T$`y^f!dmQ-P4TqpxA`YN$2erF1h*uH;X%c0MQTOG8oPwgrs{83y>P#XO7MHCgx;H` zy8n!R5^IiXYd>Q+rRbvtNJW{5a#+XN%dKh|2*SU=?Q_ltN`u4jq_U?>Cb)5QeJ)>^SkPMd0|R3d~MvToFRu;OP;2`4mA!xQvVMA;p^cygi313dL7cnJixsp z@|-&=dU-@Ychw%qme>GCCLdz>F4Lyy& z8+Rxz<=sku*-2g_Vu{i(gsbYGw4Z`Q{p0*mfz82JL5uD;Gv`rfxtN&+8o1sVu4&u6 z!_$>dPg4hGy~x$I<P>5+teS_cEQVmUxUg1ExyZv*Wpo;$u`(ABr+!Mpj)#pSC)kmvtv?Dr;bUVl#%Wq zq<54aC}))$N=K!Pyq#WAtcE1{lc9%^D#zps@;#}gQrP4(jHeByChSD$h?=6E)pn}4 z!$m_~`~!To1Al0Rm4mif5&fd>MKbpQTQQkyb$sVCC#N+{znfkm>xF-fI)xNe;*32_ z8;wzhA##pll{?cG@^NVkT}n$ziab|tXFP6bO&3uws}$<4PULslP`$raD*UT|mUoB0 zSExBXZLb*-8QBSm{e#YN#wx6szqMyX@}EiO)L=$G|63kbR+yc(>6R`gk6cJ9BCkUP zyGwp89ik&>8oe$RllLkOl^Rl0vRS{OwhFb?N|SARg4#_z7Q7ay9W1J5DcRPk_LB(Fy6P+#8Fam}7M2T#zwr7!J(9Pk zEXtUWtA=`#rG{)vJB-&hPC<3}*Hr_*r)Mv~g)RPg2(J{?1yo zw8NNa8eyDaC?J=V>PZeMTe>V2Q8p-b? zQ934dm*>$&a%1Iye3M3!-`G7hD%>$_Q;VqswNH9m^@>`O8}%ijefl%wa;1gR#r4Kf z!SdApy`>|08LH`fm_5m}J~bw@UT!DfE$y&;!Z6j;z|!CHyZIN>Mbk>-VWpm7r)-pd zll#;CghR)d(N(kuGqAFli%4~%T2j3XjOSK(687+W)wgO>o~uO5CS#(bx~+*h-d@yF zgP%}0g$89`NFSatFSB0uYyW7h0m({TQ*BGG<+!<&WtS!1@VT-HUS$GZEEOj2=~Br- z&(UIJ7=O-Ygfqg6wXxx!)uO5)oS^-rj!~zu5nPwQH^!PbI!@SITRSRV}r>^IhT%(h-IuXJ>@f&*h%>CCS1`{asVo@CP~nnXXM+98=| zYTs%Nwfbt3`Z81^=ukI=GeRfS2HHXTqd`|j*;YpEwQjPWcU3Y>((3Rpee2RTWW;*L zrN7DfCTM25)Wp!#ve$Oa5^aBE-(z$EtNo1h)@#yjtc3mxEh{}C52PmYRx*GOV}~`1 zT3wr?<^(#0oSHK{I~=V);~DZ3CB?MVS;;oubk|`uPtqB$5$c-xCVPG6*J>}SF7hIg}WKYQt$fypNAIWd9%2;`%`Y1e0-5nek z*dOc=8W&0pK2QlACtXs$w1pj$trhId^_y`Nze+S;s;7F^wzTBrkD2eh^+Uh#978ed zE_;OQpsT2>t21m(GR7%Gxmk6D&xGfM19~MXg+5hg8GRC!lX)2}0T_RLfCb+AFZurp z#0QRqQ~7?HVEEhK)Y-v)HzLV>Q)weDke=tbGPY;!Om3X?PsYrg75*CRjL~L$=Txv} z+;LZkSYs`LsP?=zFgPK6GBiHChmE06q>V~R!#-&UsmIS~k>N(6@qRV8w11rMytj6E zJ4+w|V*y8fdqG#J=%KC^=6B{RG|q4LdNOCE6iofm(?0W8{|vQ;RNV5LbB+5^WL(s= zh!}feQww>xJ}=ZV*gv>6_-$C>zYr?*Qx?m9TA3Pw?Nrm}gj~VK!PUMy{=wl(S_+wF z{K=YT`^hKVp0>bD+JTDCx#97*6z#EJ!1#OB)LmFzA+b* zda@oU>pkEv8d&E~2|tGieNV4q1NyBzP42;8s-MEQgDrhQe-rIjbrAbxK4W}oY#KS* z(bF{0DH%6~bF|^U#I(8@t33av_RGrgjS2On^Ua+c_uXmHJ!6JM{pWgP>u5-zYqb{s z+y1Y7ZF1)X?+BkmipYP_w#r(=4SJOw(weEa{89eys!g2~{=;zGctU>ZS`|^v7QFTwSh5wXq zO5oq%r0@y77f`6D(irH{cO;u_(JZ0J&@^p&D6BR#43PdXcp^60A6i#MlrTT%8(3Zc zx{N`daO&?Vu^vlyA^#I?yxiEj&UxFtE~ZfQ4tK+d#nv-QVY*1W8|>?s{Ac{}fqkKG zw14!v#3g@}mP<|PF8#e;Ib1SyO@A6r(smhBnlsTIB2{a-{Go89mgEu?1!ANaQT*ZF_j%%dcgfp#SP9Wn>dhHZbnx0-P zdrR;$J=%EN_Jy-j^qlB>?zfRrEjd& zZO0>uMNf7gi(Kh)0AubYx!EqYPGGnHAOAI9`{2BA5!K6$bO0%bo$Xr|R$J&j*#y-= zzcFUWDducf7yD9Mb%$g;M~Z5_eP3jEPT!hZ06Uy2Sp@@ELY1U@=DPNA?$4q|MvaN8 z>^f_YwG5KZ@~-MV|5pDmzB0bg0`G$-wJbJ_cLavnj#o!4^$Z2!6ZCfmuVJ#`j!Sd- ztq$i9YZYlKYZp46J>0W9t!C=b)T^FrxpM=h*c@XKTgVX^WsUJh?sw-#XtvtQ3@L%# z4m9u=3;ga|=qnxEt`^cau??gGcDr}=i{T5}-}-R19Ia$tq7<~mM18VPu_imhhTeRP z`lX*`)=Jx$Ry7TYq^!SvFT>TPh2~}Uga}jgil_;ZKSbCaX{KdzBJZL88oUyS3q%Db z0NBXYcCcf78e5NbG$njUyPZoY4eF!p3m)HZ<)Sw%hf(nIOz zJcF|*2D<2v=o(WKdplRWyQq6X#OKZh)+(mc@^5^;b~xNEv?!PwEE*oDZq#cNvQeXLSw(fSzkN>Qtc98VGACqJ@!knu)&8c- zOmVhbj*$@;B4)ehIZj*uG>wx-5szL^4Te^PZiR-0m#Am74tlQkRHOPc&7&!LIsP*( zB-KzHriG@Wrm%6pVVR6dCw&dTs14qIxvg?f=GOA9gJ)~ZXUjuPH!Ux00eiCjmCbCO zZr*E{CCwsJSSRgHctiM8*shLKM`>mB=URFFmEN2UMLpgr(v{9e4NwQAyrL*vUMc(N zTfT@**J8rYgTcUzz|BDA;OX#NZ8b|kd{M|a&^+1F(9*|J-rU6W(D0vJSc)Z=*nRz? zR#Us8K2@!nQLCpH(VOd4SvU44o6D<`mt-+A6TeAaDM`7x0)9sGs~u?x1e02z^W@kk3$=S_e2???l3 z5eWEd;DG7q_bb#aehUom9_l`y;d5(ze#g54QOp4Xn+^=D5-dCiSl@eKd=-HoMv$kd zSc}8xOMsr=2X6ZUm44aCkHi7@TPN!1(Do0~AL!R2;Ps;J{T(no1K9&K^*ZV-(}6#m zfq{R-3U5Qb?O({$WPy|aAhS38DEO&HE&zRfgx*i0veJ)=y-UDj(^3Cf6jZ-GWj6Foo z<`B48gggPkcMpLTdr|L~0WOw97FB_D76VqEjH<_7kcl|&R{^~ZCS4$prjUaRPc1~I z2i3i(ggnCwqoz3yeeXjJ?~jg=V2j z(}V9i^9HDQev1l36KI@>m~$+$7q>xO4`3V%$Zq65OvoGbLdEJqpw0yPxe-;O5;+N( ztbqpHgZ})&F9SKe2^4lMG&YjVM=jzi)DD*<_fU(<$Z(Rz7~hCB@)k?yWwF8>XZN7J z(_kfMfH7uc?#iN8_%X1_x2WulK(65|s-63gKfq%{)O3E1%*AbFRDi_7R{lahYy))O z580kZ1?U1EW`D7Rd?c**bI9*C@-N5-5FaXoqrt^SWOwF3HfK;#y9~3mlqa+LkZ3Ld_MWOm{GSCIBvGMMI45B-l`q<5$X2gWS{WuV-@0s$>8 z-ILt%E~&h{O6~yueU4y(oL)sWZxrU; zi7L=ZsC9kJERcF{R0O|4pMSb9JOunY7g?k_$W!%4ZnPP6F#xRl2A)04uOY7xL{6zH za-3aJV?8j>7wYg``;gz zC&(a(v!UYjt;p+$JeE5zOC|C>;sjv`zDt}q6DJ(R*)?(ML!8l!hlC=~#s=H>!!w9e z)`{>_;*`+;okE` z)g=E|ZwGH{Uyl=j+#kcHeiojk6EnW!MoL)9{5@PiC0&)n)+KuS=U&~m`ln5wnJ3| z0pBmahyGr{U)2oWOde(Y-L%Er#B4V%lsA))`p)ox;G;mH;L6Zl^(Y@t&&V@Pw@p`# zR?}w1gJ^Gp);?S>JSQ|I+(y67YSU}-BIT6fupvP?C^x2+c$D5o-5kCf{#X54_aG}g zTbd>hRAw5^D(&SKh+Sm8t~Nru81`v(^kKRI^6o*_(NfYjDGdnSbGlYB(Xx6!V$nB- zBlSb7q$jaa`gyti~FL)$eQkC9&*W}41f zKC|96?vz(b?O2nrE7UwxIj3=;8hs_#w>FDd;-27oXOv>tpA_~*<(OZ|{R4)aKeH-&US><74dH20N5gl<7nTB+y{2`>NlGtN zWjs;uhRbLV{P#l!wNvo5S}XkAzkpUYCn`rROCr`gFPf7Lo9Wc>?40+R8!~%-I+e7@ zTg7)y+pg5Km2jVl=xi+qH=66PO8&mtZ&FHsJfHYOB2WI5drO-jZ?lex z8XViKz>VmKk)<4e8(I;+dfQ*jYxG_A9}jL&5ApfZbNQAb)lgbKL{6xe0+oXEaw~g- z>O;M&6gD4pl#SRMand!;aorR{_o#yctF!B;A58x*y_{!E&ig>5ZkJ-rwd_}%r<|9Z zk&fvWi!n`_&Zlej)Ij({xRts|^XV6v7qtPUh><_VIhGoFH~j>TP9J3hQA==-egMv) zNyVl4bTw*l_Attp>HYNKdJJoes*9(HaGZz&XJSvfRT?0*mL9=BU&ZMW6QYDnL}x!? zBNNYww&!F3etST%Dj84q z{c4R zSA}1V$r~d9anf6OQ!BjLXXI-#1lQMCpJsxN3TT~*72pI;+x!mCo6aL4+cNOTcX1+W zHqK~FKwZZyc=u1p-d2Q9Z-Q0kOT?pM&8Z8n%44kR@S)XFVbKPDzXD<*5jSP!MP~_! z9q%KqzJMs^J*cC3+3GZm^Z+sSSws}~;G>IRUFih5G{Xq7pjn(1JOipu;kiWAfYiat zG!QG`*Wk84PQvs71x>IXFhrx5A^$UoR^Fojml)|1X5k1vzXS!Mg1~_omV^82xNcx= z%t4G<1oZ&5z(WJbqaEbf0-p+D4avr6FR@lZh!4biCQhPj_?!ePUSqvU#$72dN)+_ZS)9}r=QBkO zN;$L=E2%gaoQWs1FfZa%r{GSU{}i_L~X#)$d5 zlT2ph^>NZ?CFos~$H(vRCgq`LEih{pu)hlNLbNt1AuJgvdPR93X#r28vi77DY`Yt* zF-}^K3ZX^h5N0r%=Q5rDh@ECUbhIyaPvyu8+7~fPdHPyMWd_YcE!u5xQ3>aME~4Jd z%xBT->;(46ol(ox26oYlrvvr7$ZnyMgu*l3;OV(X(|-I2X$=kRh1$NEG?4{)N1X22 zL+j8e{RgQE`;KSPjcgS?1O5Ar6vUWc@Z+R8zlf8C4Ow;Rrv9FFkh(A*YW*B6n%1I= zfgN2ZU07iXt=8j|LHbBmS}CBPBJasPy)$hLKi*F2MeMu<_E10Z$@Cg3+8j8i^&e@; z>fl6Mb9jzQytI_UTeDJf6a6mhC&#mktbnwUd|=h#XEyLDv?)KTCn!bLgX{~#r0{oA zCT*fgN;6(W-z~LbTX`mJ#a1DPH$nP8O0#h)ae(xlc3JwGbk=t(qqUj*ccr-680Ru8 z>Gh?({7XJg9)$Jgpwtk#m0qYJ^wHtcX0@vH3#-c}DmAoeq?CMKKhFM^zNPPTt2oE-eiu$kXc7nzW6;KQX}sw($k?fD|PuqxA^N(lKMP48^mJ0jctwAuZc;q#kX~LXqD_`- zC_j4tF#M{&(GQy@2I`oTNJHNa(`SYSVOLl&RHm21np8<0PkYLjf?dp0xg*@kToy6v zD%qwL1)^G7do9~pE4{kB8s`zWU`O1Uwgz%jfsWH3({j>tJ%UQ8pBzY!t5cAz%nmn^ z=d#YsszinF(Duqjt(+9cTGBew59(%qMW$?sy20F?9}RUj&DN9kE{aJ#WGF)Z3U)I5 z&K{!9)T@W2_54@;rkt)1mfDc=+H|EOxvTvFoqR!FGc&m+cU8~vNVzYnXgXlmaD%o} zO_@uv>Ho?SiAD9y6Ri0h)*mEIwPAFx zWMpmWD>9C>(~Hq5%KXp@$z;e1ZBi!V%x8LE*-M{lZE)^+1lvhZ1M5-Y`wG$F(AdqS z7b^@K@5=6@a;g!(gnHgNsKlCtRnLvpwL7X8=V8rH!P&*{Niv;{_2nR4#Ru|bq(659 zL+*_8uIE@QUX8y%ZB=LZ-0`T*tU%|(!kf?lJ4$9yJ3Q+|+Ej1BlE^Zg44zF3%hB|N zl&l=4IIAe@K$^;;(t58}K`XB{33mw3R*$G*jj}hSl(IseVz_MVDKAjk%0_;QmX;2N zbJb2{LijVSrBs|gm8Tg`7{(jBDMr*#4bz{5?u5z&26=Dz+<~M(NR1$ats_`>=MBV63 z&0LutlhP(-cWSz)uQw`eky=`pxss!I#bp%m##D_O;fOT_NpAR&FFku?#tYBDOvzI^ zx1;)JXo&pM{?uM3>Qh`W`c&k1?o;N5WQbUF7yU=BTQTk6V) zu2bkh!3nV|V~)A{nup0>>bd?&Ima`S(^Jzbq`k`=>t7L)$py%$48m^zMbL4wE4Ytf~o>9hgFtu^IE4!tCR=Acl z+S1U`KXPD9jTkkmiu;J2nTAN`bW3Q5cXrN_tk~>RIS&7f&>DTHJkl6r8|C<5KX3O~ z`WPIvr1seVDCcBWhs<#q^|QY8W(D4=Dh(Q2SsOS9L=1?S=Nj&4Xx(I-FGcYC>iobF z-zMKeuhD-fxK1s?KG788J!5gpQCnSemhq0^1R0^<4qx;4_8<0E^hO2#4E!99XF#i@ zn#M}TUgl$#dgfE63&x?!afy-Jtb+DFJU=`=)ID5Hf2vm|jpb)@NLH0AN?EzJG*(LG zZCQ18UYnrqR4v*hwV}3DFUT14p_X})R9{*mZIFMF>eC#$g`S0t+~!x=WxW;K%zoAP zvy-S{yvX}u2jK;Jzlt^@rRf)R4xdU6^8F0IlECh=6F|qF@*R8*keB~RclwTO#o6Ll zq&f8g`J{+r+p(|N9$e|Tv=md)g~an9L6Rs*$rhko_}ud>r+=y^3F zn;_y0A25&WY&ZV`xReKR#x<}^Up|C$IL-2)D6D^FaSG-57^0w-#6F@G;asuji0dVXpM0NmOdXl zrv7iQ6Z;eK>k+RJ3pYdM^(MqSw}6(e$4c7<-s}cuVkCI&fU!qo zFZTwrX@L6jmAK~NJoyN;DulYw3y8iZV&~Hqd@O~JP6amh8Tk&U|JP$Tw*=VGx7hPA zL|a>czV?Q^f4~mzEaK02v>Sze)k;ve2)no*pf3#=+){YVwurzc@+F9TGq6Ma677D1 zWHy4fZiuu^h`%o5Ecs$!Pz!KvK!1Y1`iLfn;1>+mqt{W`{nW!=AO~}>h);t|RszF2 z0JJO)9=$1~HUe@Kzrj%xQG6xn;5)VwI~6B>hd}&>&1zKi`+$zG0&bfFDb2^u=NNiv zh#BmQenx;+JK4rHHjg|ZBQSa-eGFXmDsm5F*<5H^kf9b?N&wRN2s%=VOZ*5Tk@@;$ z+LBz=x{}XP5qOCmp?}fah$5}hO1_ZA;7q`2_J)rFUcDT9+xB_Y^urMsPlP1Hj9^Y% zfrmQaK>QjAP#<9Ie*+2rfqajd`VBGp0=9)5qRa8S5C78Mq$BG{+R!g>V*U_*H^alG zLyC9VRP2=|;I|!Kd|yUr)jnq&rh$bX@Q_@C@Oa8Pl+ z;Q(UV)z}$S;>R$LlVHC`@pn2m(>6GJassTQVDZ}^&j&a`@{H7gWgP(}iJ1NQ*e@!;E{2k^_$7fGu$R58D)MI{1N9ca z_t6sGp#f$p9(vFTeVch>;3vOhq>b2dCqYYx!`6EtGn0s&(Nb9ENW@|lFmrC`{1E;Z zu#E%wm6gHRk%m|oXj_V|b0<~VX~e?skTobv>(jsaXxPSTSi}m{GFQg0ku*WUpK*%!fInS9R^imkVd-~ZdQs90x{T*)z4c4# zs^FyH@zB6flki!65PqNItejx1W$0n(XBugktBjLNOP9zq8Y@jyhL~EIyP1!h`YN}1 z-|%VgyR1c?cWHG!{jxsh)(ov;KjBoDZr)?NX*+JWI9gfTnD<}}TdJQ|{XrIZ8?2?? zW?s3orH|`)^njRpQSDq)jDKmr8vwaQZnfub))Y)ZOZ6Ro0Gcn~~*>roD|&tdG)5OBs&l7n<1wer&?ldLu_{~y^Ut615jv(@3)-OS@!@1q~_KNgu+RB z4tXob8n>D@n4g%Nn!h%+MpbG%WvcuLzwdIEcVcz)l3E{?g_o+TW+2&;YFJ_Z)3V2s zVfxL`Upm1mtA&D7eT#Dk0uLueD3 znr_&tK8yYln6cg!Pdr1?V23U3G<3LNo&@+Sm#go-K?b%xr)#)=PZx}%J%mg|G_ zl*6!{7K7Xcx{vvdmLoq8_6?K^v!|C7auGcexO~qp0PiPS5%WPA{M_d}=|=F++VMFAUZVr24xDUInX!n?Von%-rNpNimKH zXI1Ad$5MNmR0%s|3%ikKfLP0~2IQTgFTp*bdSQ>&#N0w3;);onBujcC{U}c27c<{l zkG0X*NzMF;-i2P#chO%TGILL34E;T?L(1LfvRn<^ZC#Tb18mQQPFys-&AhACR5@_eS@I;%K$+5eNy3ZsFDMvS9r*ZZi`!aV4Z8hRr~szr@Iq089BI<^7!+V(fn zQK1O;g_>rVN@l2kV2dx+d*3_JPlwuso%$52H#ba*a=dVr@l->^keCx+b*BuX=g!3~yb3tI%9! zzR`i6$k()Wa%^yQbKh}|b|%{{h2>{u#nq*`lI zFeyhw#Q(#L``OF&LBj zOg!)`8T2Ldq&5a<#E??ZyurSZR=FN{?z!taw(@(-VPV6Yn7KH8clyPQVmZTupS16p z3({=28F?!@J9<-8hX~o;Ux;TG>c54V(3!y4;7j?LS_AQv6fZ%)%%%;)p`McahWg4y z^xjN$shVq1#EpoNuI1u7s*SSVmz}vaEh24m`pzuBudP~+ekvxoN=4m`nGka*sz^i! zM?;|#J;%7O><=vn&IxS{Uq;S?vW&zn<;(MznI+Z`t#SBps8c9Pd1h|n{;{ocXGXmA zq&jkW)hrRt$?cr^I?bMTHGNce?Ley9omnKEcaMo06JyI)BYLLizGI0ngHF}I#g48X zObb%L`mHsZ&_%eid?H_myGTXqL&7aXX@Rn#3R(f?wK&BU6*VM!V}#GXksE3h3dUql zNS~XUltQIn$Ziv?s}E*J+kc6u5mO`Ig?u}sTX+`R9sEV>gE~q6Ik+NlG?*b*)3%u! zy@8v>FXbzJZ_>A5L!DPvQw zXMXaHR@zWS#2&8Ahz9vH))jL+;(rfc<4{DXiQGxKue|{N^$Am+E6<%`egW!gt-3h;Kzg=UZ_G}}>FU2CC+QK)8$q)lasBMsa1nkEwpCe zT9kQ9%T;D7+mxp2Huyzfna3fYH%8{DW6*Ak8HM#l+9NI5=t?zbJJ`&p7ia27O3672S#qdoI=0&y*)zzG@Yw8U3 zx;jEzr>{05Ajh_X?zhHDGn<*e8xxH;#zs?v1YMOahM0t!TupWfZ3imtnqFB`6iHbV zeh{v!tWYQEZOjAIzf2@wStu#yh{wg6;x~vJ+RId=YgzZq3g&O{*+rYXpg-4xw#WhP zl#Co!SIk4mkaZfE5f5zO)954gLHYm?UhkogeFpxlf%&r$Vf?G7>J5#jx(N$X8%UNp z)?F%w2{NA$7xS6@j@!U~!_H=W^j7*HtXzq(&u@Y3ITJp(NASP)Hy@kH<`?9biv`R}!9-!qBDX zLYE#7dAvR}%Nm$R5;UD%K&#vXc4aQ~v|Qx2Ob0$9A1LF;{GLFXC%%Gm zdOI|$XV6xg02@`2x{X=ggchry-%XgwOSFyL0T{Q5QS8FpJ7P^oVGV;o?wmyXEYNHF z&{kdOD&?ScCqT0<1f14O^fnB3hu=WcZ-5J_53lBGtoC5oIf%Y91$yfSXr!y4VcxT% z=q#=S7Q?Ez=v%OtJfyl~&)tIm zdIdZ|#el7IV$B}o>7|H;A8*yePB?{Ge6gBh9)q#3ld(shVs?wHqIuZ}92Rs_bE)~< z9ENO;8g$r(NVB^d5g3WgV0jtSk$>(1RyGSL*$l%At7{W;yfGEgv>{`l z`NA}tbSRWtDVs1>z$0f(D{F+U%>V(a7Fq1 z+-i0ZI~5#k5X~cR-6ZQr^S+rMkyGoS%bi5zZaXtS>{*)(Q-5dFH)}xS8%7UjS-uO< z2TuMI`;p#Y?KIZvYk)b;AO0ZE55HF`>e*&tW+zuyOpuP+irCxQ+KDW`ohd=zH{C#N z%vEnGMG=d$OD_QX^d#7IZb3s;jK%uDS{x9x*UYUznrr+ZDa*FU{@FHH^syr?5wWUO z{7-V@awEJC{S)MXHl3a$bg^5m{GMf=x$b(79^wtwWz|5m(l_#4`EdB6%9~56UJQrm zy)5=F^TCQT{!v?nTgwmR8H%aL(!cXF>~8lh&wrkmF3mQa-J@R)b;uo?*)#pe^q8#U zUP1O5#kn-wWOunpU*y%upFEo!Zs5=>m}$yAxd!47ZYb@wN>)GSA-j{C1Dp0d`iQYq z`789B|GaOcKQ5G|o}_J3hI@9*cX9XgRgYceUM$QoCI{AMx>I&1R!uscGAXNNFx#jk ztZ+SxIvl$&U#ZxH$Z5_k!fi^{zL#qUX9YipE~%y9F?z>U72gR8zn5)Bt<+P(MnLdi z^?vWa6?`4GnG8SFe!%lC=HJ+&F;gO2**h=|)c?H0GB&1c`|>dPhYZPEGF+IhDz$XK zkJ=jZAf{_{hWo8_foY&WldoIG*soQ@?A4kYwODh2b)hm>1p6}Az#k`Hh)gS@(CW9_rDUtOxyQW`7wm4#Xn zb1$NwdUM;P{fMEg7M&PT$C)Y=p&KYkz9HGq(}$<`%AB7q`z|SI))=9Jla7dpIvdq2 zYNLC({TbhrI?t3;CGxQ|UYtYUR(AP%Wc5mWner-aOqMrS3(YW#^A{XjBPv8I(fgxU zMQw34kXo^c#$u&FXiDHqV29jB{cNPsJ-KeeD8z#AX0}p_u|wOeK3A56%gO%>oey`= zE}9K!Kl@ag1TRCim^o3yT|>p4bc}k~_c?QWYDV(TR8Q7_xd#w&G=a}`+=v(uofBO( zCL`*TtDN+TS!t|7Z@Gb*!NKw+g*Up>aa=B6La4*{Vxu9s_0j)Q`=~9HdGgcHlJHY? zn~`lrGjI6@_Sx?IQK879?mN-}cB(O0uJ0X~c{MF1ZF*KxZo}XJtqtRma-CBn+C~+K zc0`YesO}smHf8P_os~_YqQPpxR-vr$1wF+&#MI>Ga@p)7rZip2LTrdOUY!t*lQ+v+ zxRqh~~(aCs$}EnwYL|B`2a}jCk;CdsXVU5S|Bsgi?5l*vCtJ8wVbB|_ShZm-F?qYw1@Ju6z35(x3cY6v& z?gWM_(ml|AN9e=cHdS>)c(nXOXs29IsiOt;&+y-Wpx-hlnXB+2^tIL-1GHpivQk=| zro|f_tp-dw|G?JTHQ(LKm1#>5QkV_qHKkf`KKwrIva9C|@$L!ytQ0p7vWLX2jt}l4 z5#u5%d2*cTkR^RgU8}e5Q5S`e$RYV|SXN3x&WkWR0-M_g*aHr^8Dh*EdP9AnJ_YEz zb-*n&6|ULZI`=zI+sBH(a(k$=x)xp$eBz7pzRESd0|LLw-L&FX9GeQh>u|Mj|LmUP zTJNZ6>nt>5>r?+3=d_Y)L#3=TTggyXsoS+{`UfKt*!L%}m;)tfCK}I;ZsvH)OVwl? zToqx9)WKfO-d>sui4?Mt{zz#c%K@AJsBfIVDdMw>Yd@JXJ(J%h{b#T4oaGdp7wwy+ zKEiJHJLE6Qf}f|PdO_K(98jFN{SJro`o0Y&gc01gym^5n0?pxFXJ%_DE%oV_5()+Iv}nW3iJKhMaXV+-{_;)*Cwe2)Jp2_YDX=YD5y0!cH#h}2!$D7A*#8<9Khv?h8hqa1V@pIHWS zVXk!)d9Io<%NQO=je_Xw9{+^v%^sz*tlH*kJ*2Ku;=*0zA@cWO4H*_Xo8753%%9v6 z#EJhQose|VAtu8HE;HTfqgJf>m%d4R29M}gHB$Qe<`W({^jMIDb1~fUpl}hcU-_QcHg?YdRxq-Zm zU&h{~b!&#{G}db|>X9%TE)njdv_wz+ER9NF7I3YF`H13vE!GqJ3r%@1+mPuAL_t`; zp@r0a>Ls;-=F$y4+1O)R@D)9Qc6J)xtH<<@%p|52^N5M!yqtrt&&_3~Pt^*dWQAUn2OlxFKQe0H|&Z* z`W|SzA*|D7bE|cgx=9aZ&LbAJF&o9b;8?_%*JKX?<5AC?qd!m!EBoYEp`)RRvKelw zB^t-5I_zQow%FKa+BDl~+ajry_z!mvsEl*QB>je3R@oblSK6p+wJ&-cq7$aV-|Myp zzyn&0jzQdd4c393=jAW+AGvYtHQ=lE7=yK5%1=OXHw?}Wz6puSVEutLk?kq$mx?Vw$QG3HL~iZU)dPA(-g;g3p=w$r!+588f2B}9Sy-nUdLA7f`3ZauFH z2gEXB2mT{+W6ZUj#%%Q$xnOXX|4(0ie=txa9M;xS9r+!|KKjv>gUlN{Tn8QTwn(89 zlL7C0U1h0!K9n4KD^F9ZXm9j#SeI4iM8m6ZG^Utm%&YL>g}Gs(CY7*tleUWugj38( z^O;&tzUtRb4qocu#K|)wC_@4CpZX^fl%3N4G)_#scCCS~P!AhKB;dOQC!6X7#G!qGr({dLsRe zX(&DA6`{4kSUFSKXw~N>hwkndc`x#}h;+w8KHB^xv_E@K>Y=1SVu9pK8I=OG*+UxX zj>*@qz^#IV;@3q_be|IDS~bG+0*`%#{oRALlt^`wAS5?d!fMyf){^ zHxXMu(>pzot7KW_gkg4@YnN+-1q!pq{#t z`boUtyyw>3tDPA_7puP9DECOl&l#<<)BV4h6KwAzE5z?8e5p{exHirV`f4aEectCY z@5jCS=flX9D!z~&VcQgQvB3I5rwcZWE9@yCc#X56I6ve2%kK+6Gv;uT{fINu`P{DX zug#z2Io@>{6Ej-mr1^H}jin+HQE?XvPANDh-vCE*dX?Nfv&-kvA7^~5n0Pt8a;O<~ z&3-LrcYIQORQ`!kP~Sq7KhPxwVr=!W}D2b zImNwKl*dB4yGiV~1y>YY88^!@k4_4A%>4CJlTQUccT7sl>Z-iwD|^ynmKR)GASue_ zT*H5(=MPr&74=mM%nN(WbNo-X)ArWxxsLw)NUEFm!doF@eKzYI>Aj~bwmzN*v7-t- zEATmHxn!euhE}D1{@5vT4BeLZsxz%p++g98_{{cHtWQtXYKI;N5BhiePZ^8Z*W57A!sy}d zh0YzqPkMr{X6Dh9X^GR5?`O{PmouIT&s?>lHs!k%yF4!`Sru4?4SC6E;`s28aUMR0{(-gLQ_3K^HGRgR#{3$&CStp5Gh0U~mz$bCD>3zB)ihi7 z9|46LZky(6A6+=#t>_XFInD%eA^TQuqRv9DqF2ggeW$gOSuFe@zF>BlWuRZ)m9s+o zjDz%1`krH8#4m`lUSb<#{j9Y2)yW!_G9smJcEQ{+q50HazL~xinn(5 zj`X)_Q*z>cTjUScHO^-H$z9S@&U4pw+2NP$+zYy=u~pfnwnF}nZt%HZ;{xnts)!M* zjZveNIqDm$JF|()=icjHk2N+Uss@sLCjZ)WPNpx|C4cQPDHkHP7)sX}Q%x z`7Tg7D=9rD<7MW4@BGkh-DEC^e>(ngKX7NcHab5`30y@wzZufT=p3_)9ZuH>#JKa6FDVoaxAGDr9*`wz}tPR_~Ndb3ZB z5}^*>gv?fH1u`aPZS(dHS23!xBcv(z{qDBz*Uqbsw&F6bCS}u~>yg?t&1T)9Dl>)Y zY@?6)R__9f{RR31x6#(v^~OEJ-Pe&R^tO7+@4bsNm!vF9{h0A2J1zLPeus(`4?0e| z9(x*ihP#&9Px0|gs=*-l%v$xBwhhRq`H0);WUMp_8K=!AOg39vYUG;kn&?V%jux&_ zXVfje+SxtR-=}KnkF!n(enhNUu5iLJ)D`sn=sE4`XkX7aMZUhF>KOfrI#$bq<@^sL z$|$CP)N}NS)(cMIPD|fKc-)Pg_nbWcEpjN`_WqPrD*a%ZmeD!qMWCcMk($Y;*{-?P zxrewzuBP@%;%RP<`JaAUpQ?`63j*;}%^GQ3Ha-}iv|MvDdzTGK2i#j+Rb7RgGx%KV z2PMWoG{=_yOWM55qgku`f2j4WN&FN0_pYj*XiuzbxV@8DoxOxHvCwjM>h*!#cjXU?ZJbR#Pn`eSgF*#sOIY&9WyhyAOWTl9Cug?5f;y2t%rCL;a(D5( zb8mM2W&d6*&K^Sk?{nIJ$}?>rG@r@9;Fi=U8|AGxdNt;d=nx(|`bOm1b8Oqi`^L6# ztw2sDm%bvce@1f7X#X+w6}_DA?|A99c`ABjr*7XQc4tPI$Mhex`RYwQ9%!6y);7qH zSq3~)#v5)rB<*9K;SmL$K}Rd$gx(;$#rrvZKY3!Z z?z&^%ls+iws|SQFRJ38vp%HPoV79rJ@Z966uXYUz4{ zG1(Zvn&Mu`=gx^N;O>vQBGVvm6!%Ze+J`LJyVBQX*YH15TGCluZTmdf9geyeJAZc+ z7k^~NS?je#^}Jd^Jz%teJ!6uYs6Eu9&Beworh_OFP2QQRtHp3@bhqiO0B=v*P5 z3)!wjW;=&DXFJ9*V~sL$e((5 znrEPUGU_t*Ao6<{zzh6gbT$q_l4>K&=k1>Oh&7H{E>#FpXSBw_xw+lad#5eR^kin{ z-cgWel1dV*+C8rR5l18Ty9zqLhgJEUHQp$xby6qjGmQMkD{ZUZ-h8GbA2Pp=$tRun zG(DE;N+CU`efqZa+8L!Y;=R4)JIV*DqIlfi+0!Fxd*nP%LsztPj`5r8 zwCmxz;e2YQ`boX4M#D4evJ%)8!W}-w`JE@(mF1f3m?qSwH)&0SJ967+bWP8faW|u0 zZnNM}rI&Sst8ZK7S{czYqNC>rR8uD+bm{o(ep;C~IT5F9l?dBO{urbC+L1eoFao!D) z)wB}bmhOSbnG9H!z6DzHU--WMLd4G};8AP9KiC;a)X~82twjda3GhSK0%rCkbjgy) zyZXeuV}3+St>Bw`4QoRYw9pi<`iR;mh}3=XX&%7qFuYkLQqP0-=AgEdNiC)CA)20N z(&7{nLPqy`~aV2SKN}X;SXE~r0oiz z5Kn?miFpxiL0AAu^xA*0$&CdstO<`>Ayjs14y^DY&@vLejzqntdGHf1gm11Z=2ZZE zUBd5LK>Gd+6zwVM3SyT|!=E@BpZbB$or*c;x8mUAmEZww4h-im_z-2FPD%7;9ngi! zTd%#y6fzYxvBm>AO%TVmfir%E7}9?9RC)sa6MTA+$fLd#Jtbj$ZLxMNFxgI^TBm>} zuVDWw25)UacvM61iQd2rw*g7qA3noQ7{O5Bj_)8gqYFm96ER^QP+2M!nDB?FhqW1b z0lEWkO%TY}fWJM8wLXRD##>mK$FKxE0Zm?@%|wiQH%2!YnCyP=`)$U4up`=VFsf!P z#K`6&R&_aE3*p0Vg8f5kNZR1dCG|oJW1hrgN-7enptg$frlRG4um(e6nXG~Mk>(id z804%Vd52j%-56Nr@xYxDiWBVkAnfBd@R~M)ceWAyv~7TMZ3N$ONwgk^IK3docnKEV z-(aEZ1`4&q?0-fcge};G|6ueMP|~&Vtv*03^v9^D04+Tjd#oSc=?!miU-+0?qSq?$ zy%)l$Ie4|-z{7kRR*~IUHA0o!@TtCmcb4RbNn#I4g>D1AkUEaVfx>PM z3vVlou_@Xl{$?juIt43r1Nic*z|`METcmy^sn|_&MLQ5x7>RiZzy_1*qB2@cK~8K^ z`H^IUCb5*Hx^g7&zNG$VB%%?&R!Al_o=L6V7dIzOn$Uf1$(X;xL0Fv z29j6Xjr~Wekds{BB6N+s=ub-Q&PE}1s#gxERfjgQWzzv z8O#7nPihR4eA-{vHwsTwz+6aGOH%KYRBo2>nHMd6LF;}{fl%OU{4I-}=|`_5!}kN6 zq%Y``L>H6#ymw^IHhH%biJAJ z3w?kYNR@+4^s`mh+yksg7ILQa1**f2x)VLohGg-mp>W$=f%EVKCBvq95vRKhS||oWs$GQOE>8NHaHqZ+<}qf@|PmEs!&54Q`eG$hfnd`UVjj z6T!E4gF3fBg|m3~Fi=ok5Zw_6RLcnPs$uZEtU*4e>xgK%g0&b1zBLrlGxLF*`3_N= zsOQPFHh;5f&`D-_?CK4e$0qQR6hzketpsW?5H)9k=op4OED>D1DQ?;Q;8j&36i*$+USQ~X;HFV@B~Sv~qMn&hf^3ZzPNv$=K5{1&paglw(jU=jZY`KUthU`(ag0{LG7D2sX2b=4D$~rbcZS!TQ|c&9lrCzr-pG7Q>6|GPleXGNIHuSON*(#V zOj|2PJt$v6m9C1u_rB5oTA}Ziv4%-i;XaCtqk!{!*Lzn-M}mE;xC&Xqs?w*8t;P|p zxpFZ)GCWN7%TK~h)IQo0qdRg?-{y*nAEenf+BQZ!z*k`t%*xu+@bkb(Ut8ZX?*!lU z;NoySeFF6_*F;Kl{ONk+PIkX?zH&^JB9L40s&!V+RL6y1hF*nggrY)x_!-(BVH~vf zFbVt;sgC`K>z=zP7agk#HgSX#doLlpooV3fokB2kD%nhog+(VOl?M`)8vR&q9(Ge!2?FgTe&%lEJ4%n4edJDuGl(GIcx>yyt z%j_F2!hX^AK`M?MbnE$+>|Cpm)>SSTDC@nOJs^8}PAlJp&}gkPy-Y}O?DCw5q@%US zY97DiFR=l8+uQ*Z_`Tqbz>MIUP-=LE_O~$)RWjBhy8Jj|riU?)>FrD_X}08%YS@=Z z&4nMi64W`}lotj5@MmSu%O2p}?;R6rt&gI97vh~QJntj#MXidw?tW$eO^9Hw>Gu_0 zZW3%9$_dp&-KNrJH2s2VWKOZRm@m|GCMw04J&+Nlz1YjK$X-~~gfjF$MsH=E|JQ&g z=VI3V+=QGy!7=J%vxt!2G21;cs#SE^sM!&}JO3xrY$@}dvLqB893E&N6v7*nO2!xJ z6*6Q$gJ-Tfm7u%e_giOXQE&OnVj{fJOKpS2Nd7W)KwlXy6|Cz^$Vtvwo3qIKPiTg+ z$Kr(y8|7{g857kya0IpTQ+@fwU z#+VO{RHlMp7xvnoOS8lq!naHz>V$SgZWc1Uqr9EG|I0la{2))$o3hh|9Q$SWZck0v z4lg>#*+l*qdaY4W9i2l0MgR{Od-h{7eH-X(eKz-&uabxX? zj$-y=&Xr<+?pykAbx3%He|>K8+|yZH^)_ZKsq(Vq2@j;PiV`P}2|M}>08 z>fKHAggb{ygexLXZU~uSf zRIEBoncOIGr~NhJWiyc9GfVnIxXFG)T|iFtZt7GeMcJYj&=%=y5Ix=AT14MKm5Ttd z0q2d0W*yXlZNW?hmTZD_k6q38m%e3rb}oIwaO(BLRCs)7Uf`-+QhpZhjT>?c@|5-v z`=O>5WiM&>NS%d=+}~8HnWL*}S@l=N1K)aCZKpomxM>cfhB2R+(yY&_W`4BR7|%4_ zJcG=uCS60CKrQ0VNTcat%s9qpjMRQm-ze+h*OavXg-02)>D^WnuBR}9pDZpA9|%|Y zg+L5mrCynJt!{cxjW+J8$Mi17TfH4J#yz#p(W|iA8sWZpLPgN;U^PMPA?~aW^mhzA zyNC`SZe~-3n7w8vWHB3L&M+3h;TNsJv2oH z#@3tE@AMh?k0ZsP*hv~A%@-pD8-Jde3>mGOSydmT_tpe$j#d}8oiq9*Lxf*R#BTBT(rqDn8T8B|{yA^U^-U6yS4%Le8TYg9v|5-Hs7INlJ=vtK^ zxom?5(-m3iNNtzX$gZ~%lHE?or04Mep4c%Jf$A*|t*-?%v6;x6_&;bheV~gMfUMWj zY7Bjp#GSekz4r;&)_%x`BSBm00S&A&srCl? zegGL~Fm%pDSR0B$=KTfHgsm_hf;v78xz|A{$h??qT>{3|g%NE49 z$Z4yPDR3tAxLb&>e2pxHnUJ)8fvkAj8iDHMPf=^@6y!>hW3M7&3rB)>ACQIg79uJK z18KVxy2J}0SPp0QtI<+f-?TdKDQqUc0Aaaufl6fa$qJPG0_CqUL2&=$&MBjd-T(D07hhw#chSC!ASO95J zg2a3sl6Wnv4P6IFt5o2EIY`An0*~|x7HJi+svQtfxfZ(Uaa6r}gE1a}guEWvOnyRS zWKTSmh`e$^>WJBh`j*Z_WNH&?j#ZZKjJ?m}Y&AqoII2i=J%m#x6`TS$Y*BZ^zL$ z%@W>+4xRlt23PgtoCC_epy;pAf+t}gmWJ)E2=tUR+tDlcA@@;kMWYF83aG zD?9xfr!5XAU?N??91HZ#b3K#(9uX4<5m%j`x{g!P8qv>_QHf{=DyMCMj8F0q6}NWK zL#$8cpNPmV539lj)Xy``-Oy3)z{d8%dIp;Lfjf*o`y@b#R`0ZWn3!@WwhtIk}bw}P49cae#>?x|Fafu#5?bYpEb*q=* zVF#GKVIN30bC{RfE%pjhMz!Nlm<;mJLQdR7agEL+Cx0lq<@>e5-OCygwlxD#E} zMq?M~pNfn>3yh}Bf2caxmp!hRWG;hRJ()LpN60SMOd6H)&LFaS7JUObq(4JjiJ-qX zTcQr(KC>{ivO~-$y^8gxa4g)Lo*{IT&v5ssar#-Nq&a~;WKA%;vJLcEbPIa5F^;Zm zRb~D*1#>K_HZ6l?uogWKC;YTkn_fq?GP*JG)-v-q#%Taw&#g9QScTXoR#$Ti`vF;z zYjG5^trex0KzE6GUii9nMv9}cBv(pHufcIL>#Ak(z}c!R3WQ0 zQ;N=1N{N10bI%A->MAA%e7re#P(8&ANA0^ch!?*G?(M`K)Qah0)yEtq@Z|D{ksc1t zcz~`4d*)3>wGJC6=$+7*vlt(+>u&bAI*vVJjfad;k&aWf5_|+iFg8RHhNn45nTg{g`Lg0COl# zj*JNVCWrz3gm}89sC_wI{~P&LU+KGPA5hT!XvBe=>BxKA&vJr_Pf*{l2erT~&z!}{ zD~)OcrKw+;%X(Y-9aRyTY@UN=J*W%tbB?9|vH}Lnt}q9iW7&^ZvMRDgnfizidqCII zzrnp1XTCyi+vm8cK0^Qgk&cBOUgaIjm@-56*6YhCf08yeZ|~v%}4z6NpQY9 zR<1dpE{$wYwK-G$VvQ6=hm(LPJEEOsSR;XbZSB&&5k_cn$i$?nsoWT&koAdKYSdx& zoAb>N~U%s^~>O>nkv=#yp!I6x!RdTaoGw-@)=Vv}cYShMxsY%8qQ@8HPmK(X1} zGDLyTmKucy@pEWioi8?3zd`QV;buKr8i`;!TxS z%(0ea))NHnr7=@_9JaVej zR~wa>!^pMpft`Q|?ObM>iRx@rO=Ah_X=?ggrabHs#pt@!4ccYI!E12IC`kJdRdkIy zO+QkPah=$0p#*W1=`ecnUDSpw&ookpaT4{T#<10xdwL&K25qHv;^$k1wYpp{VE#&2 zpOBN_KJp!HuncC9x|3$^2w^kHrD=Q z`mitLp3+*i4&9miGxV#ysoGmR;IxHen6td5M6q4XRyg5JsX}zR{x{>M7Mbs;mu69R zyg3T>wSS=Ej7!XU#FA8m4J8-%Q4_NWpQG^fG44#b4_^W@(VuLDcA2lHRWcenyn&y& z>RhsXT0Ek4r=GIULPczS&CBXGFe+ItYpg4;}sY0rsFgl_sAGT_h80pJZrOt89@$S zDS9c*>1kXB@=|u@Ug{66?z~OQM}6TU!!5X)g779Peg@kH!brpCZ&BI=yBDG8WVfdd!Cdz6=w=x=0 z@~_C7tG>8nmdR7V3j+I|qVz;d~^;m6V@eU^GtN((Qh_ple01wtde zrde02r*xpc<-Vv-x$}lkyKQe6lC5vW&!N%cCB45<(Y_=Q4=iydrGe1E9EA$L%Tbw+ zMgFQ;^gXpXGn3ye*B6G;z5K@_ChF&c(GEea%`xT)wZ8N=yq|f&2IMwk3HbU)Ni*bC z!0-pn30zZoEc26NW=L~h?wZJSXL~He}L9x^d|0e&3CbPO21`XjwzbxqPc`4^H~5OEp);IbWb|O(8mNTJxQq_Czh_d(ToJiC z_m*?Z#rXwv2Q8c5r;ac)q*>v4dQ019qnTcb`;5Er2|G@nCU)hxz!l!dw9#VOcF3Oi zoVf}=Di1&6Nb`s>kBf(`>mXxTjrCUC9V<(zFDy50<`TM@ahjiQc#-!uRhxoaH`6GI z8?6@nLNB4E00qoibYG=3J)WzpH=(XFll0|uadxh*BFEh{bGtr*ItDI03ZA#i)Ldq= zzR9w2^Yt9$L(FIN=(1E^^VTgk>8(LuZO7$%niLO_W<>+(!^!@EMq+rX?$T%TDSE_%rS75<@8^WLY^|U z%`w)WkP!pa6^)@!@?Ncr^_nhfjbRY+Yi?k>AtrA)lix6?iu7AuWGQNi)`T5GjWK33 ze?qEyMejham*3%G>|_=+htdB*yAI*ro&;RG!?;g3qE_Nb8}gn{XSNuVt=jBy)G|I! zKZ9SiqBVrBN;iSkxfk@otISdTAhntqtgi>|+iQ$qZW!B8J#(HukXp~wF9{n-E=9$LeBc(>+jW#X#ns zmdGFx0jaGSLmN%0pO_e94{pBEW;^;0e0}Nkx6qD$M3srh(Bfp%L@a3*GFr|;hNLWL zMv>5_JL8j{$h_MGwLt}X4;403AzAN3bnO>ZfIf{n%d@B``Ux_gRD~X>QkL1z%El;n zz!F&xx>*FYfhBY*h5H-QcWHQDB={DRQS&(kw77~m=$FVLegpb0>KxPgs1#!xp3~sP zUjW^r9$g%|^F68t{0$F~OY1V^`UzG^x;f&7{)LV^19tl3(CRKD@6H0`XqtuomO~$z z56Pqy##EVlX8sAit2rq35WdXIup-9i#jfHi1f*cN{#OJ2AWB(9RE`Z96<<8sz35 zp@(;eMxuh&PocfHgsQ&cBB4eH zykyRa_zpo1B)|js1kXK(_q9B{Da1D|p)KNjEQV1L&s#%SCklZ^uV85rVL`YK>&sJE zFK%E55D#^6v{)UsKMJy96m->wd7jfEu#klDTmoolgIvE2bomG0%)+Y#Y${dps)o5l zV^ji0{4I1r65IVT&m;K=GtLh^u^gVrfOn5%@Mj@;%4jQyUb8@nf-@jV=#fzt1SLwL)f7ZUlia$M z@b8pSc$;&%#|UZ6CL8;>IM$^$c5OZE-xlzzipX&N z1U4vA)0l?u@;PWhvJS_iH6Qw^oc9;!9%KB3J@W{57m^p7RQ!m;J_zCY*YJ{71a-b( zRwRpc5_W+F&mXCA?8H;VcP?Q)Dqy}edL;Rd?XWJr2Q@T!RR05w?3jH%(A9>gqp<@o zVN}GEorz~6&|?vN-^59!h&2oUCKVBgXEqVS2#p!a77^{W8!8@up{CPDyBmP>^I?E{bm#!pM;K3p4_JlUIA?c}MeHip%?C<;0VU$Grq!^%g)uh|dM5QJvhhBth+Zmh zM&XZ{C4Z$p>V_(LiHwh;zj5Q*) z%}E9H2=q>>hm(A+JXVL)InM-*l0d5fc1#?oOt3jcv1=@hEP$D7`1C1wwjV7LTtXR8 zvpVL@<7Rz=)k?=x>7b_uu0>8Ai&1jm_Jk*u0d_C#sJ{{ch3i@Diwn@$nQhB5pXo?I4_#_syB6-)n z=&uy!CgCjkfLwE6mpuVrNkrcjV7;t_o8=p{NUEAAV%7piNov27jOdTBU!Gz=5iCb# z+^tQ)h0B1Z3QkA>BO<7ulQ=OC!TY~pd{w|{8)3zY;VD96g5=4@9w9iP7|f?UehBKs zl}8b>&Pf<8LC-uxZzK~vIgtfHYX`oagYgh7&TH&-QW1sBlE?lkhh19{Jv2mrB-aO( z$Lk0W^yj_8SW`d#M|$>yHz;{)p@Cl)$MZ$7mXV+gV(ZXu5?-koXBOt@#QGBi5RI|h zFajsW9D{KrqHhKJqXhacjJ-|n0J01Gd7NCpsn@Y~BAzEZh}^#9uZo?T0?LqTE=gE* za+Ag3`(ziD!tYr8p8u@iJ_|FmW99_wlhfXFQb3q@)Iq@W#w>WRWPA~EiQ_=&}8m}n;*oQB9f zA3-M?twrP0qS$FgFe(Wr){FPaN+x0CnP`h}9avHEFOpZ^nfDCI$!|l;1@S#{^Gnzp zWP~voOBLMH1u?ob@a05&HG%~^hs*wkTGYWCvyKLVZBHd9s}!}AFU8h zkRLrTkcS9@DhutPQLJ-D-fkmx6-wjAXoeH#MmuD8XM$d2&&T39B5~iryDH>>nvg09 zm;8V|^cYV?;AAzzzSnUkkHSN68MCPYiQq?^$~Z_z2VkGOj&-dM-Z&7vlS8J^GvE-P zz)71x2I-8RGjN}7g*V}E(6BzdVc%j-uW*L{0GHu#zQ+LZ*BSfaU)VvGz}NE}e55US zY*kSBU!3=2xcM#MX$Rre8YBJ;Irac<7Y;YpIQYR@V^&Wgk)8ktV)3nRkmQJjk^nto z1GsZKd{I3hIXB1~-A>5!*RTSmF_t=51tP)xg%Q5Q9oPUk%x*a2ad`Iu);q}e$!b{;4#id6xO^Lc3uwl(0`cM z`@CDI8u%Ky4>I!B!NAQz{Au-Y-hAlw2B`8L>qpSJH9);6a1C-U?bvx`aT45E*C+4^ z?FL%uVO}3)&~JY1kPMvZ&)9$vV*&8#s(9ClTk9qEbTZbzByP06 zmS;`BUnLlHP+&XsidRGWZqSnS+s$${mC!doZ)YSZBgt zd2lmQQ-+Mzhn5L%A+*dwn>Ot7B6yNW6hwj}2vu^+Wa33+G*Tf-e2+l_Cy@SD(v^iu}sj!0L<^7aM`Nr{a8Grmc7L^4K4?qIT$NPQXdmmp&a zA15pI20vf$IiZsalq`=C6$e$_=!x83MCKq=CG)4yrvp2LV0nw;siK$zsm?~wzC<=4 zNM>@26SOn&w3DhUM{D3vM7H&&Z&p9kY+Xnh+g_)OjHq!#g~egntt(HTgUq zyouE6sRaqNBKje>II$0;psfsynCxM4f+FxDay+pQkh4OvfGPNt(3{8(Uq?c86cw`} zJCeK;!2ejRBb~P^Js1nw*+e#q&TEgz0)$dTulOp15Z#XKSh531Ef~UEWPIkwh!Vlw zUSg(1PqMI1PPA1F6e3Xq#F{|#Fd`)rzVH>{9ms1ph_g<5BA<}f32z`(Yq-4jNmeuo zpR@lzBXZJ6Wl~>Wuj!x~kqU?|OgIqv?pJ<5MoqB1Uu7-Q0$CLapB4lstcV{XG25{> z2_GfZlZehhFyZ9f64}Ou7nv);UXxX4uouVI|uv3853w&4_+!;dBytwJ^9h8FguJ zd$L9%C{MI7BBzjj^AUeZ4I9F-i8Mo`?Sj}pCGu7v9wQ*@MK}cEQ{{6oPz;cKYBx46X!JYmh?=~X%cN%+!+zwyYfl!p3 zfUmoc?0X&Us~EWtt3dV?88MOY$;uJ@H@T6>Z9zsxs7<&&;V)k~i4C7d<5U&Jn2LkK z@%Z1@TOx$@I@Y3pmbIc%rz`Wrrgalc;O9o5mz?o4++%g1+H@Pn|B}Nh zVLK9#_BA$AQF_jqJqI|ON2%p(MsoX1XxW|&+E6#+W3G0+x6eqTc79ecS5EScpIMG> zaUC!DF&h4wf30<8OE`&TF@%=T35_DFoBK9ccS?cPoFQpZ$Bvr~m{ zu>+Qn0q_{n15c2-ST-}c3{1Yw?BGsba2h$`_d3$b5M?*sGrG&u4wm4dUENxdvOqC> zl$iZ<#u3vXKsB)@yjJL}RjV-_9L2A1qlGfIu`}CtvwHWQJe0`!7tyYiBgDm{Exv&gY{i3~zru0B+$M3P2Y|okN@YmV$RUS}gau32;S>3@* zwO*wKJ&Co|c?QT8*AAKCA#G&Sn5?|h+A0ZZ3w^acOTGVR3bSWkt}XO{n~Vq>_y(UA40&j6e23Cq?DpfMq5RsvRAVA z-d_84_VcrpA|Qwf`+YAVC0iYlDG(AaG5s>D02%4~rRsq@y)wU_KUd&(BGn#<9{_PjmA_i|gp z6*0~!6;L@UPx(}kw@*2ItEfV}410uCF6Tn*=Tk{m$y0t+O?lZnmn(Bs20MmXq1=X5 zguMz_`J#>5Quc`Pt%z@BHqJf=>~Z!!Z4cQ(8?gev7l^dVR#jA0Rh?HI)~cX9ss^iP zroRW-yCK+BQ;pJ4gxD#Yy$X390*`_;H7?k*?01nJ&fAmrh&{o(gzp!vK%4;2kg5!J znY7ZeFEAI_ELFf~msb{7HQ|n2U~8!A1E0WK z8F=fbp?B1Ad(>XAmUV>Ua$l71C;8V+uk3+3CcRoI-%q5Wy96CH_+|m0P%smU#B6mH zw^da>`&4DeDo~`6YRspad=GLw4Bd-Z^%7J~fcH`Ri~Yy0vwQ3Yy93A%u=;;?C;y)3 za|#G@xw8uQ2h;1-Q1w(@R=-BIRLwYA4Xi42zOt&#t2&Sv))mf`LWLNs#H}~Yt0Zfk zP9HgkG?uXQ88A8no)^+M9ZP>Jg)`@YF9^;2a82>92<L{-~ zD3u9yYq7TMSQ&V-IFe$WEaWzaBN=E)5j&N$f){8)T$97M%23@P(PzOuiiY^q1vpm1 ztB7wYsFMW3EHLxJt%Dpr1so~XaL|%`?hdOc{LEsHDruZVV@2vk=6#&?aAh1=OS#I! z6@Jc_b3O$QrBL}Sbd9AcFS3!vHC3Ts6(mjpWj;`bfH#|SmATu;83(vU#>%)e$r^{? z{sA=M05Wk7njN*r(Edy8S;93J`E-uY;WT&hSVj0>k#(EFBaw=_>MGR$S*e5kHQ-1^ z_O6oF*f6xoV)qz$7Xay5)+$WX=L~CFa1aWe;B|&8VnB6{e@}CjTrE0Mz%d^j7n&L9 zp9vl!ds)14fuNFV#rLM{nyH$@L4hwvox{TUk&R-cF9H@pRSZ^Z?QUdWesPFjwvt%#+)kf!7T`>$PYSKGhrR^H3e#h=m1^&CCJ>mqxfN@JM|pE8i{9M)_I zhON|f?9~Pgn?UQ9ss%?n^Ide%i)6aoB~%ifH++t!@yTY5imW6wz67=>puK4NS-aov zLKgo9ivRe0#O~wo89p5Z??PnB2PTU3g5Z#e`~+E}BHuNiyqpUlw<3*s(4sOJ=Ru9e zX>1$vw-FR+1SJ|F5p{u4{EkSnNKp}xoC43IKyZxrUa;Sf1fJmA*7Wy-z$ljFB5(02 zwb-*Mw66|DGx=Vfw-0Mtot^T4C5e`Lfk>oGc%2QLLOao6@j!X-N@Pd0PjKCj4D7Jm zknizgIW&Iju%tXE52i(EEhmuAT2Rme^=IMNte zHA};k&2<@2%d*!#R@u$#B-A+oU-q+??0=CxgbU#`9*R3+*xw4!R;VrBQLKJBSBNdi z;&=!;1%SlQ+Wzzo)xfp_GVDUjOelTXM@GP*47iVhYYEy{0qbVLLPPfecUsom*pA3^}_19Hrn=&R#_vb<#dVVh7=)c(ZEYAQ=J35gH9)*-(fzTVTTLg69*275cASdwm>UHA8O&P^3lMmXrK6bvF{SW zhSN4B#+~J?c@*1tJ}m>6pqlVRwC)stFTs!V>>tN!IM7C-A@L&y`xD~(|K&tJl&Q=< z)v+QH0qZml6~HP6_ED}*v4&W@Bk-aadn63_GMaCb}i|Pkj1iNW~%wRpf6L z{E(%~2xrB13Jf)omIgp4zU)R`*YNi`JWL~? zt%f{>SySLR&#HUzR7dP~tmitr#;(9B?PZsXz8R>V0w7kVQCpJ-{JwH?v?JtEg7lGp-?|pFj6p%?4A@XV2 zIR&3{kV*vy#a?;XPxh5)NbG{dPKp0VX2fTf^U8sO`RralZ6PbCsS@UhctDBgBvurA zcn*%7Mho{M58}5ZUXr6iOR+T)r3nmTTSWJQV42Cf4S6+&mi1Xts8R!X0^lBDy$JhD zWN;1(bDr<=mdq)@Dq`^mvVNzoKuLN74bTl-cRT**6OmAE>7<$@>B>{gTN^Jibcv`O;6e?=OE(}Cx|U{ z_#_e&<9^9FU3Qe$Wek15CKQ&aK|F$F9U2M=KfTD8$fM*4l7k3tLU)(z#23gl679$u zaaOs6obHF-Vv)qsN+c%!`&1f>i_lFd=Si;@0?vHoq%MCe@~XxwA9)dd5=zC>8j->J ze)g4IMEvJ|b`V}jynZn)M+e!fC@ot)@bv?62-=3z@Bf>J8!MhFpLcC!Gn<#tKr(~# z&@#&X;x$WIS-ho4Mv@gJW|ll%G~yEf9%Szm;3Bb7Wgr*pl*2w1_UL9!n&V(|%sZi3JXVo75Wwa*4=A?@c-{%3x)ouvl1$0mQ2dKRoa;z%f5> z@zDwjdDHt#wq1?0f@>zbOMWNPE&NEZ%Q;q;szU(~oZyr2E{48|e-QsB`JKpq4pfmi zPG}$CPKhKmdB0f0OYkfK{HM}uNR2__zvHYd8s%`8KqnF<5wyew6@aM@wpFqe$sTfe ziMOnfmLY*wG%p6$m(tX|2$jyV*9G1s>>UMn$xlvlq!b+yT3oheLJQ$titEHT$vqKh zCv_o-Uu$E9B^DG5*POR-yiOV#$*6^PQty%6>?l|q!%ytQ!ikmNXgBj+GQcvf^01mv zULxB}{u1pf$J4L~OlQcfj&V%vM+}N* zrSFp{RI(_sl2SjCEKO{Rc(Tj>#lwn8tf}N2Vzs0?C$>T2Gx5z5Cy7^*T7<-lV)q1& z6lYREB(bOPReX+Uf)~1qr;tcbR{NBBT}+OVd<%mPpfEe5%+M(W*k|ScqI*K<3ZzUHB@M zRDnezZL!zFL!r4yvQSv`rUra&gmhKsn?!yg=vIMq5{n5Xs&ParTSC9eP)~R(`XiOn zQ%IC#w!#VFMG>D$(iTc;CE|M}hnDD9as{!Qd0?2$K9Y+_{mGN&vPie=AsQug4YR&* zUG9u!K^=Ce0O#YZCK4gL zNYs%7BvRjqKr4wDqUl4qU*YNPJ zUQ+9jSWI{%G8}>mnQ7Y*1uw%{vFs9oi?y%)(4 zr2?Ep62udn=9A=!qG!3#Q!;#s1OmuVCAjKK%jY%h>;dPiiCRQkDsx;irV#r}g;w;f zoPEwfX+;O72)dnymXh9(4>^-sjzsrzmF!uQ-90eXzFA^L@yM6$o@72Q_1q*hkuI0y$Rb@5h2*iOSY+vN37w-rEpjAM zT?R!&zr}*fOZstAy_6%8Q^{L&Gzx9R+ep=4xRBsq>HL(ypL1~NFj8=qzbAlDC@OG@ z=ajmW*jLFh#VUz^s*JW*Ler~(e=T0pZMa-b5g8L{DCOT==q&zDs4V%X#6#jsL?0yH zae-ViO5vu|3t~VZnT+%qMMoqP76>I4ld7lmg``F*HRQU)&SIl$@s>VHO;#@8teh8~ zNKPtooy#gx4;DU)Oo>mDx>`2ZUxcRFX&WGwB9StebCNaHg7V@aE2ME2%%$ES{ydh( zu9Bsz_ue`Ye?`xmF@%ZyE~mZ(@55 zwO7$Tsp?4=u?EM4`j?~5%P~s|_$%WT4zbF9ICdT$p5>cVsU#ve2RxT^-Y^`OI-t~5 zCBDdp?_&F;sv{XoO{ggK2l*@(CWlocU|LKMO=KsG-kt+$ks+y{1=7CA0izsnl?%@!WXgWKDZ{8pCg>Ff_0IK zqUew0U(&g)1uP=j;v=Q+C$(0Iy~KtI{k_-|i6JFEl`eUNBjwzE*@8&@wi;_xfWw#b z)9UOdxtm}uJz}vQS==FXIFFT(j9co7Qt6AQwNfGnseDRgRyi%d5`9R;wF-Qz3`CNH zOK)F%T~*Fyz;p53l8Kx`_r$76wMnXhxzJUj&j9{S{GjxG*7LUnC<>wAR&+!(MLH=` zzmV0Wk}eW?9iAo$9ujX$G%b;ucn#^thSFX%1KNqyymWR&eoNu}Zr0k(6{opI<_pBqv`>xWVJ`3h{%snNwQ;a8f)>(S8#=N zp$~ID$WgJ&QdN*%L@sv-{t{nF?k@3l8T-o|gJdSswfUPq?=kdF71*5{$$<(zvL6p8_F8M~e0s6bJI zoJa(D9Ql^~C}wNJk5gEy5cCZ|A(?w|vA13zY7Q)II4iZB=0MU(ZC78Imi8NaNj;^n zQbX)LcCfl#eFVkE0sm;Vn{$oSc>AGks_tMyW&tuR69SUQ_|#waMmT>nP}K+8Znwx z?n>>m@7pi!7JDsMioH03^=*j`Hc~fG>5;rnIzM93#e1}ZOXAyh1BJvVqLoLXsZ@NA z!kv>?Qn8;Gsi4*4x(+}pbtw-vEQ*|+i z=L0rF2e0bLRjq&~PkjIf*4mHMSo?&&)iWB3E>AUa8=6!0c6-=tFm3Gy)m2B-CY7t7 zRi$c#Zm$Qh>Q(A1TVmSSN3ef~R9LTNpAGgW`=b2-{O8&-v(VJEeUOl6!F)U1SZsT$ zPt^x$edz)R9#w0h^6jb{bd`R(b<2H^hHNZ4vH zx`q`b6EbMTCbT3$m2tnF0}spXZOFqd=)gid4;mDK<@feCsMQ5|$W-gtwI?#wm3x{% zg~4hPJl$@)+fU%t<4E&T`-c4%&h!1(v(kmnM*jXo;`*xI$j_FvZq-!tke~1D&33fCUhP3QXW84ps*@V4MyW4YYmI$W zeXX8VAKI$6qwS@(u;cf(F`p}|waTiY>OK1aGO|4hy>^=Iiru=% zN_CKdp=vc)lyI!G+GxQY>kws?KjF{2_)M`0`RL{>q%4fI3`b}Bz_%CegUE0{H3iLj z1CQK5jbPtN?AcPi3dc91frZ%1kCAt=hi|HVNZ-R&x}NorPisdY$<3kA2K2Uq`k5WK zsQG$_de%N~E|~(m(pI;#&ExihYNF?=kL*|WPE}Di(>0O3F=)&OV11XJZ09Ji_Ul~u zvk6#_+OO^Bc!A^g58KGThUNBx#XnG^*iKgy@gmpTcI>wXJU_8dL7k`6F6{pt?rN-h z;m>zsCx(E*A9&q9=x`$>xvrW6rFJ0aVfBD|4xf7tI!?7euul_p5XyH4-X`j0tVYbv zMsB;P$B^_-?L_>>B4jFCb+(Ul#V9pSZAgtm-#Ys;_UUSHIf(WivE89h9c6Z_&!m z;MNRWE}+rv)os|mtFXpb!NI2ZPKzCpTKzfvKz;E12A&R4U#d^odlY=Bg(iP$uLjem z>LIMsJil)Z@9v~i~LFqQxnKj!k(tHb(5Z0}9CBHMXtlqn^fM9>bnaLn4+Fk?#YOmG%eqCpPadTW(%QUVldpmw?;5 zwjmNLS$F}F&jYF_R}RIx9bnfyaB;9|dFmcywKZNb3dG{!>p;EZ*tP-Kt#)8N2{;;{ zPcw=2Cn9&p?K1lav}r}G&;u=L57!&on~=AO*uB%>97{(NUm*8?z_UWE`3SUhH!xSl z2OLr|9p>8W*!xFlegfUx2A`MV<8B5H{E_`w{Rgf;bH|6^cQ@yM1=|Ly3luCwCw+L8 zS5$wbbtNlEPO=kQv;Zl-LbXNK_pshB`#m0gyxNTPy$K(xvih~^B-f8dGaYQzEns^X z3o#IH)DVxh$+kwS+Tax*NA8c?cIq=Vo$tr7IoZ&o8xV~|&p+UGFLw0{EW!|Cqch0u zXL##XXvzsZ!44?U1!|v#_tUW3ufX-)eD>piZbsfmgMD9cX-H(V1<$w|3mQZVn?u#p zSjR?iW)t>XCSEP@-iSQ4g^zhiUp_RxWIsjXq>9uXX@3|!*bGm1V;`@CI$vW0mZ^Or zwf08f*@V<@K#On2k2Xhkz5%yN#5QI2E@VAr=i{&IW5vcHWqY959ISBC_J^9s(babB z?7;#}z?NRc^;@Ck_x65OuBNF4__2EGtlE$4G_}vcgU8vag&l7n#%pyV_La(^pQ!2) zR_Tm(EVS=nt&SlXv(fbFN-V{C`wASAS=Psqt}0mVEbLJVY^67zg;qCJzq0EOaCa1x zoPm6AQXk_{XJG+vL<9HR_n^@%IMD-7v!AQF;IDS@_bp`MUpocZ16Y9-c!{-GJjn#> zL*lYna{q23Ryu?4wp#CkGqa)!9n+E!ebjU`Xwp(UID5^260OIKMlrSEM{#L^Vm%SAG!iW;%^vQrT0TZ<>_iL4KW(lSda zU8gfh{XFc+gIIwx*u7=;ef2yt@H;Xj@~|KK_YFF92NEQcK2_BJfTJfKKqFr=1Nb*s z$)wl~XhtF}lbPtyDroLO!({HD8r+uJR0M8*&K`y6qtsrjp(D?t?b%qCs>r_74bPy* zTd{fn!n;je?**>wiKg=Lg%zop*Tf3Xfr2%$2IJL}>B#p)I#-gp)IIo`p3rn9G&zOj zl_23a66-6DxKK_w_z4)hXj4Tsml*Q5wEeBCKF1PNMs^-XlD17eeU3G9 z(YnP*(pEGwh87$|!zJrK05!X&{nX!J>_Exd*cru<;aK%DY+xqmJG1JaNR9N4j&j{< zVu-`+FHb%( zZM5Mqy0ae0n?gaE9hNB^53$f;XzIsj*Fh#_QX!WdcQ4ww0cg%ZnK+bciIg@+>TkeC z+|N4;tGJb`q;s+ZD=7VRsh}MNiuKq;$s3muKm3fuod6%PdbhAj3wXB?s5d}usX1KE ze{Ml0V_s8eli%=?|$ySzaFlffNl-25%pN*QRpC5K|kwAwk4g9)5w?9wxl~7M~@9O`X0TJnQxg| zI>t&ad&w-@CG=8yJ5q7(4UgQe-s#{qNt&))Lt$?hkt-t^48PXH+kkj1D#~UUL>ah8Y|V>Le|NIDpIFt z4acuR#-w5|oiTaBL8{zR|KE$Q$sCr%R?-=%1{cmFQBp0FIz)sBQ>MsH>LyX7RVo8g;gDI$x^SX4-{hHxC>}>@zfvKS%Bj==WKKuAB4@A|ad0X{ zC$<9nk6`KWNh;n_O}v(WgV0l^;bgi%I@eN%lPaIgj>s9Q$I8en-i!D(sVB-zkbIIS8HAhCkEqD~GTD8e)#OPtd7eq8 zo}@=6RsPG*M_r!X7n%wsr4}mnM|mDaq)nb#lFp6vII{R8mS1`mBIi>1lG?Y(j95xp zF9H>1t$d(A%q|{iU&u8l&>fkYlG>4Yo&?bS-`ZacOLGgc(Ezf#C+${sOf6SEZGCio z1D|SB5f}-+UqG+#$ZYnJ8{ADT<10G^e4mA;3(+Z=kZplfEW!I#!oHSa`7JSB6^_Xi zdNU&0s@S@3fooW!DLU5gBGtji?bwVVr} z`Pg~g5zR7=fMs*$ec_|yOk(d%t~Lt4tGcD@P5oH)Lp<+7DE$~*{s;KZke`ZIe+^x} zABZ;-8CJrd4ut2q@S+wzx)!$V412YO3svy5($6zgGDi`sJZ+!muGP?SA(7xrvab6% zKbq=95RTsqk53|hdx>{XL#sQXTtn>s)%cl*_$;%p*}%CTUr~y@N))gPT(05VHAt9C zMl%2|d`dh$9K0n)Tn|=f+4Wtd^cXTI{ifDLX>V}mQ7Q@pvCdZz>-n+sE9^VinSA`j zNc#;M76HC@Y=0;wor-xxsS+PoP%jf-Y(Q3${M~3@g?15ghOnATb~sQykL*dVHx9YG z!wy2OY9oiUs4NWyo5h@?21agB2bfM1?|w;aPzBw*58pNzO23CNv|$O>H&cB_ zMWm3(vooIgSt>f8kQd#GZ+Z)v%BP0eKrOOu*nJg8M`K4F^*&k4UVDRTsb#k1W7`96 zy#g10DLRn-1Jw!+4<@}v(5Il*?K&h z_PFY9U1GaKX!`HOVnukFL-srKkh;b8)5pQ0v3kz_g62PtEJ$ag+>SG^rlX3kWG%DE zgl1A@+h{wX33KgI^3o$}wfV*@rw+Boz79wJP$_M+^kyrPo$gX&kjJE5Np1Kg@|b<_ z{XW~1TE_wVoSw(^-N5KQaR6AW$_a%oqYJ>Iz zb;cafqsd{Ho9j(8d%wL}KSWmdll@MO)hpoCqf`J&Re$rM3YvCk&fT^Wb-3@G*3=wc zGbhw?Wbt})yE(y!1))tsKww``jy>4ro5q7M8O+Tbk zrqCWVzhY^(Vh8R{F^gLYGFHGN`-XOtTYAUA@H&*Y}wT`ax&A%GPu2eCKJC ztsgahEaKI+lU?oJYF{z0K=GT^OL~r;Xp^$o%fUX8yCskn&H} z8aqM{M_(G-nCk2})HCnbqx47}rgE{@jx{%F*Uiz5ZHB3)M!F64B03`dRH=KN8f1Uf zk0Up?>XT}rzKB)4T32!IwEwtE@O#gzh?!;nGsW1y4dyc&&}(%YYHv@Qf7R#u6>L#~ zov8ElS#p9Hmi9CCL+Uu|O|j?AOQuvatLXX3T(9ral{6Cvj$@nYQK}!le}J8-kGel0 zfv$NDyH#SA*$lU~Q^9OE18mJy!i+|5Cb|dASgi43Z2X5N(|Jn&NFDB7{hU5;zgD&3 zcYpmowywIK?|Aia^{M{EnMz0JF300EclPUi^@jSM9aH9RQ`r=m@>CO(N`2wx*)hP9XT7{nD{3#Fy1>}HT7MpXX2y8 z3#s1bSF^y)kFEDS=`7X*eb;%iv+fT)ndJ%3%^sMyDx+K0kC}nYD&a2vfPU7wQst!{ zirgQG#-A=7RD8B%TS1k`g0gEOQ{x9?4Rs3@_HOX~&;LqzelS1$Qus0doWN}F-#Xy5 zu`5l3#EwMER3zFx{y_Yp#O&14__{<+>V@RVtsE zJ76k^w@I{!_lk8+%t};9o=r?itW6G92Z#{b`TGS;5FkDp1bk8O>0NnDrsJU%csBe^nuPwcbAxY)epPl58fDB>>ClB=H1{O;<-<)(ASs~ z$r|oQi80Cd;~ykCC!db4PHsxv89SYb#3m(j+(5$X&Me*&^5tx!H+#pd!BJ#vWt>!Q&p0WMV~F7Q?@_4t1Q3thge>$ ze{?`Xr@nV*oBPqU550ALdp+y?bNzpMpZEUhukF2BTc^Ksg*lV@)l5#!P0UK>B@ZS7 ziTuPH$p*=cq)kq9qp6FjY<%5l^N?xf+^t*ck3AoH)_4#2Uh+2%ycet$s1s}uS{10` z9~9{1|J^gjbB*U7UC;iGT^pGilXxz1ZM03|>Uc0ZDbYUuTD(tUTWVbD@6=H|+A+1u z8L9vCJmCGuiF=y(-tt_l4UGPc6LVHpnsw2Xz+X;=`B{(t<-$t_8?i+QlgAm_ErW!Zl*)N z&g{oN9yA`}frivA=Mp6~AR6zle#CF?R5kP>JxCAJ<$AR~tZO=%P8G2BJG=C9Jxe#h z;!kAN8bla<$n1VI?aW7}yZO_tX3E?n?wzK;dBDsz$I-Hpb|ziT4&+ak*tkFOT|;8# zZbTPd)f4O}Q}89kmu~^xOZ19g2F`zpz1I+PNw=p4@pKJx-D*^4J8;irqV6eb9of)U zczl|U^Km)`%Ypg`otLoo=rbHudbRq3u5WL4YD|rHEuDiN$j9}znyq4sjn{hV^e4KjoRS!(@e0|By+;isVW%v0j~c&rep+kk1XNzT5;< zZRzyHD}Yfo?!KMs51N-kKd)Pr`?|XVki#hTE(d$p-Qmcqyzk+HDIXefaf1o?@H?{SxkWafU7=P7a_w8wP}PCz z^7P8JWEN6eUqI}BiJi6p)feR4pYizu9rM<7#g9>ETgksaQy~~j4lI>E>3|z5CUvO1 zTtOXBp15vJy`+o^<#OoRm*_eJO+Cwfr-8aUmCen>|EtI=wvZ!c6Zf?u>dhykxE<&Z zQU?hkJr{{D){*lxqB7iutBT0HYEzGw9>+HOGEsG3Vri*P_@L=(vKg80G<3zo;F3q? zR)LJC4e(0^^lNhd3GBX*3V#%yTcY?D#Qfh0#%jI!P5qBNtr^`jd9vp>cK@Di^I_J! zmHc)988x#T444D9A$OPg(N`@p5l)naFx`>;m|+Lfr|h zUF`~XpKhb-8Z%R8@%Jsdlk-(0x-g6FE3;1PC^u1{5Uq5DRvu5DwY-le9@8DzfFNA)0E-xEw#cK+vv)iB%J{ZgGz z{;lS?wN*&ZaR2qZF-V`R|Aw)K4UV}gZ8M&b|UsmRiyqk8*E*A_fMJE>=nAYT~EAH z!7Nc7>;hBC$)!>?)Q)nWa!z9{lpSx@+a0>AUSRti7w73 z?rwOoOD`d-n_=&E*HF9PY9G;8pc${KpG|FYr9{ZIpFvC5KT%R+{c*%(OoA*=;yG9*#*D1f*tF>96 z*OLD`c&K*zF6=~W^|X7))7H#GJKMVZ^oC@0&)aSnPha$WsWa3J#Y#OxXLgEy9$z_F zpEXsP$!STaFN=8-Ke^)_?keotpY9f06Zx8g*3Y6+^D?^fxvs1qCFlOcuBQs{gnG$# z*N>~AR7SR&xB0e(oOeGO*NnzRqZd!g&3biJ`BI^G-k znT==Mh1ENO9qB`!YW2-+US^jP~=jNmbFec+NR}!hJGYhawrpdG}`<@u4-1Cba3u>a#K(EzX%@j{Sr?4 zf6W?_-9CG8#?c%n=d19m;qSwl!6m*n&Mj_5)y=IJYZQr>dyA%&jVisRv_iCZbYUWo zoHkEa_Z|!^^Vbht9sb6DeXx;lgfqaiOh0KlCe|eCnf=kDv8l<=qq)&@k-wvLqc@bl z5UCNH7QZodF1a+dB(cbMRyXwY33d(Kn3aW--b=b3AwF?;U*38c`T4c}2 z{3>U6?%=F1v%U}a%Dgo&!q-}FQ)T9^WLN0kIr3M@p`uk~rIGgWV5++6q3`lm3p6C- z7!tZO+&-v-aqpu}YpORhQ%-zh?3UPyNG!4^I=%d4X{X54vX>&;qwV5XBz7jIL~@;S zJ=DJDz0$Lqd@wufc=#a(kLTwkGd)>fWYr7C{9o&Zo(J^!WJzRkba837(k7+d%KJs? zN7^Qj*dqOxGsTw|iUs}%_6t`Io(x1iYn=bEGVR^jv8J)A$;GjbWr|$%*Rq}^*GDEq zrbO}kTG4LNIc4vb)-L}kb{7|&rIpM7DSNH-y|QrR_VQkd_oGk6N8rVO^2YVk!K0ZsWIqy~ zp7mPJ{+zcmXN5n{yc8TB-0pm!-?D$1RC&t@NMJ6+O*7(bV+l$e1_PrF?1O@#4zmx_m(K)Y3JP-m#A&a}qzKda6gf zA9%L~+J}G6c{po#<~`Y;=grBU9$p@*8J-ykI(=++vp@A>+03$j<)5s?>Tl|{+Y`@5=9c#^f4*dC(Xx`mrNc@_mEIotDzYMa zORAOGp#F3!2byF&mDx0_T24{!_?&mLzs!0yvqI>qK!NvX6*9iW`tk|oeanYMW|z$? z|2OfIsX%;tukWK^VQ?hb@{-WOU|s)Xp5^*eQ^)-{IAI4|CC!RE6^$!iRXU+; zXxYQj0m&C^7yY&KeDGxE@a$<>8*(b-HLEZvCo`*l#x0>20;8M{O~+XO*r@2~@}J7u zl+BC&mn?Lv*|z#N-`HT&P%v~U*dQDZwei(+{=~zcPV6mfRkos3l@=E@C>&Gxd(n=P zk)?;q!?Bm$t#+HIQ{b75`?81Tc=P7v`6~R8J2-n@#y_D~{Wm(3lWSt5qZ6We(VX&1 zkyY_^ZhzHG|LOeXZyQ=4o*gO;EDn6;AK~qxKXfO@v!ZvGcP)FO`2E851x*THESz7o zq4Z+;C@jD#{h}{BRGe` z^or66rO%fyj?{~GjMYqjXuo%gJS%+Tf^Ub1XSB&U8)^}}%X_2e1?NvPhefH$sc%x7 z+&|3-lQhq%$)3aBQt!Rqdfstf?VavfNQ5=XElk~?JQRB;vK-xLU%oc-dh~R3P5dgi zNX>E9dfxDF4;~1G!b?M&0zRMLyTdcg8N^g|vFkVE%}i6_#4K?q&o88+|@5iS`Cq+9%w??K$uZb;>{hFv~UQye04NutLDfm%vVeqElD*uiC zM*ix)Zl2fmi#$eHOyu*PX>X>POnQ;S>?8J1st+^isN6;*_L}+09gw;zxh@`y*N(p* z{WW?+d}Sh$sGaIegcS5_@#gv$`bz`*gPnpS1K;@<`|tMUdlx$QF+Op~OfjFkUUz_7 z&)j4}rqKP!d~513B^@SnKWJVsL*3_6dy?7Eq-U~oa$WMX)ChNxxsG1ZMCSp|7oK^Z zRo+K@YkZ&i&Uy>HQ@!tayLldSuF~g;E!R*1sbIe_EzB)$b@wm#CHEJTa{n_wn){gA z4KhJK&df92Oi%NyyTEtz;-UZ%8o%JRd04k`e8i+F>PQdj z9b{9z$ZoG96a0ldRCm+OwzcEj=IYnvWHP?-`YYp_9%`qdhn8w%H>GY? zTU<@#dP>b@g8MqBrS9(O<4km>Q$x8&&(K4m*MF+1zDlp7#xY7w1+v$elf2!oVivpw z9Dl<$H&5AN=4JAk$I!d&?r?RbyV}+_Khde0P1Iaq`smiSu71We)lb>4n3`bDUGuA? zx}|D_jCRxWsr0|D2kKVNFy!bd`ze|8uk>Zxl9y!IO4K_(H&b;}a>zrb5_Oti%x>F+ znaLl`t>h!?z_Xa{#cgE0=goDxf;~wssIBc!jx>-=rKkRw?)%&NF}qf2`pdnj2E9r> zW<3?M@zCzHSx0`{U43mH0-yirCe5(Rd4}MkeaO72I+`W=glVI@!1e2>EY2p2UBw(l zifYks>ISNer_Ht01iX4bIcy7Zr)QXu?nnLVxW0w_?`|`iY}im4s!6u{F){cKGv6$= zt$=nIU5^w`N*q-_TSK2S-GJ*7Q`|+?;rW$JQ%)ZHyDBjEsESTAeYc)t9?%`tJf|al z+(+oYjc3Mij%`NfQ$YQ$5!I{j@C+|9g;&M=OC_tm?LwZ>OFuv_=wULw9pptTssCLd zllqSCR(qa01-^whU>uf5bkzT~c_)NdwVf6H9U8mgQPp<^i! z9#M_;5bNl7OW>N18rzrCHVx2TP}lRZS8M7m~U%uwX<6y1og z>9+r)$EIiZKc$;9m;CHA!&3|TIPEOCx%MeXQuo9*$H4sl&R^|F?#moB3|5_UJ~g=QxB zJZU@YmgXsbro)guMw!RxuUDn#&#t0YbdYR*v8lz*b;zH4Q42Y)E|Hb>(7nx8z1E!4 zKbhrf2ffzM^b9`TVD8n|QE`}wy?BfH2}M=pkiOb_^kHguN6Zv-PxS9eY{K^{sxG-h zbWamg-$0E+SS%0nSxP4PCREy_+Rjp?c1uA=gQ$wzd-nFJjy$id(3N7vj zea7pX$eh=iolLCAlx`i4&N44KCGPdk^QHlv-LCdIRo#8sam=&M!|p-4@#8eVeq*ZW zQFekpz*8VEn{VLIcr@il^m{0)ufgRCUQsmy*}!tMTRs+nEk+N4npG z^_S2$$VAT#>Ia@`IB7EU9oDCMng}@7(apf^X<(kgEXXsqjsBR)hn?nEruUz;`_(?P zNsTn0=x>-XnMa*t6uI#Vwb7iU+SZwB-mCT=s^HI3pBrl@>Fw0oPSauk1POnbd5H<| zX(71fJu}I%wKPyHnWWyT@~tWEma{irY>_COoZ5t==q&g$!p4lsl9`4 zbBY@AZOBbc)fQj)AX=G1d*`7yZ{Z0~V1wlMfV0quke-grKZvznU{Y9uJo=WK;Y1z# z4|S1=D#u))zI~qR%s#t}eQQz|`Vk8hqw+nM>5?0$g0`Y!`j_c|MSKd`3#$z(YUJF{ zJo7VBW$1SLFf$gfse1J87g5)&#N5@3Hm-J<_WT{9YQn8Cs)6|wxu46_LPyiXuF$T2 zf_lau)T^6OMW{sG=3Qru_M3a{40!(sx@z(6eW*@$Fm0VXsI||v4X`#T>MzqxcXb#3 zXE|0;raEP2urc&(OjV&f)Zn+cu;r)FRGz3sSK~}++>A7LW2WSP^a8T&!}e)?KsRS{ zz9VP;vJW9UBk6O0P9OaPEO{TiKm)yuE_Z9|x+yhO<9Vo27i0Z*(utozpZhkRrW{Kh zhNuAjmuIpj;$NydU7w}>hOE9dhhex+b((%-%@qHmgi-Dz)SKQ zW7MXTJonO>icXf=O*N-469&t%oQJ68{s#1iZLaPO&#z!c;5TNlR$^PGQ6ZYn6&+=LkY}2{V@7-r zcJfhr0t2aZx%7|TQTf`UH%YL*gfzBe3h-8DrbaReJ(T&PFIg{yPd(1x|ET9L!}nc} z1)9b)8M&D;(^=FP&mwf@1uk5RX|^%KiAEio>ZCMbB z7y41=Ya;A_R{fy1@m$^8;L-qW4&m|sG+z)E9&=xGC%CH^sEj0QrtVA~PS&NHeK7fK z@|k3h#Mh}ssp;+><5%}NPk6F?E&Y)|LGXsqOQE~M_k<<{p9|#s+jy5b{gsbC=gGvX z=)~yc_@?NN*sesA)O=H)Cv=;8%Dt6*eqSK)zJILuQSZObT%_k#vozT-u`V8r6-Mrg zHjW-Hzc+GQv{$r8v}^ouA~*FD72x+g!+g&LHU*nxG|YS`vqe^itp8=U&v-4|HCW*9 z?tRB$7SOItwM@>9jff43yjNN&Rz1=@dNw{k*$!>p=Zy6X_w@*T;~PSyV4t^!Z-M7K zEX;1x%UzdvH*rT|U$jSTbZkPje(dI0rTFC7ocQv@9m$H+4xUhtI#s=Q`|b#Yf_*}N zh29Qt2@ejB437(q30@!A=!<)1Ivbe6d&`X^V~HOlPsBcr-BMmF)+#n8zAL#uwbK;Y z+Rj|(PEU!imv^Dp@qgoa!PCX_m)>ZYIEZ1#0+}$M-#UsB8lgdlam># z>TX{;X@6tahdK#oruS7}%y-&9ArKFo4O|F39{ANC_6H@$b0YMDlICXDlS;+C$%6QQ zv2dbuf?<+mANN75(h}80|K^PH^!42D%_MHW+Vh8VjV?#pHk(=Q6|Tpfl)AvxkEM@>Em7Q{m0wh*TUD2WPx~nEsJch#N=p#ok=S81YNqW9<~&b?$ck2$Y8uQ-F9ZceUKpuf=%>(;sym>);q|6;bUFOls< zv(mh4UN=KbYv|O#MY`?syG5;` z^4-J(LwSwGf4`%?qPO=0{o_)VP+C{iwRBZoTQ|ZYd3AvIIdzz)5*OpAhhf2QqAym; zGisZOW8NlWnt=WMACn3Fr^2>7d@#sl< zw(^^pe-rV_ub<2Bf;&VXN60O(e#Dxyfkh_s*WvYiO!4%jUn#$uu$oLD4_eC8q-!~M z9Zz7kBC@B~$j*NdgUj#k_oS1ul2~&XN9y8#e_`)`n7lm+o_X|J52o=z8}T(s{Nn~D zATHuJ7t-ZF07mlvqgYChR(=oG1vYthG)d%GO1vh|JJcthYR)<`L0<{XCXw}ZW5R7R zs~0kv`!i79#O&M*o*%lIzWo|{H8Qi^+&KC+^D2@1M4KXF{{nA#Gu--@zS2YZ*Ex8@ zesK6fV)-ke%CF9(R0roN_X2UspQfSn4sr8&B7?)~PV*>!d%S&2*SF6QA-LvLdWv>D z*;Jf~?wK5mW zt>*-FHGRFa-b^C{+D44h(+s4eyU|>4^UWywYUiw9UyrA_hkT*ASx?pI4fTL$x&4w! z*FMa#d<&2MN6fmN8Q8vLl0DV;ZZ9eb3-n*i5>8a3&C5=KyH0;?>d_IcPVf7ey_<|E zmz-h|`9@{6$L&Y=e2gtuj+qFj?k8(`9U5JUPQ7Qp(?2rv_&Z(9s&vrKl70WnbFE(! zkzXKdTSR_%h92D|GR))5PyeibFi|Esip+!hpu3W}fRD+bd(hcu+LBKBE~*gAh!K0~ zQ}lq_kXvo0t3R0>=YK@Yi$bM{S`TyRr#9 z1K7N_x&zW5QcKk~vdgn%XPxxD_6s6_DP$>!$>}*SP?izJ1@$()a8cR;|4mPQux{WHtH%$7@AR4Yo#x#H{{$}1){(lhV)SSLj z^G#*vA{ZPb3LirB{W$XUy}sxUV-CJAb*;NpC8})QSYtZXoZ3tWoWn}@q8hWEUtzcj zjNjwz2Sog*fGa@$e}tDneJxVm7yUeJ)&a$LWMnt$FJ(p>O}GoL&xVuFkPojWyBkNQ z&kQzC{Q`)pIhEm9(U!!DJ>c7Q z=}ChKcYaRB_61J~dx2pzQzK<2iM@UY`|`W_47r!7TKM$+Khu zw^E_I4GewiRjlzVtmWt5J?3RI*4*mWHqA|mI|$!@*d66Yi6=gB2UCxnXI3IN^4!Hz z^@09dk99IVFM6KvZt|}3KHzIYRMXn~pm(6Rne!Vx;kT)cK4`|eKe|)gkKB9A15`<} z)k*r#OPEw+nidbT+g#+we_iUbpTq~mZ;dsJ{t;;&D`7_Uiuen$jCf-+D7D*sq#yLW z?f*Pj5PBn{ZgxTDi&?F*&t>(=@P;1>e(4+Q>8C51&B=;Me|$vbwX(6L3rc#G{Si46 zU6gpvY|~-iW`Cbxjc_Dcc@Wdh<6E7>b>11iNn$Q(R1a4%Py7nEjd=Qr1WfA zhw?;uX1rJ8bm9tT0Y(z}t_chZ&&V2*^=VeG?B8=@Stl~z&iFEvPv7<`XE-&yhVBFL z7O{r$xzS4HH4D!~swJL_-VxuLYUeES?(`1xRSwn(e-g01Nx?ROCq31vR6NI2-Uo># zvEq1#pdy|?crtNX5k^3ALZPi^>{`k zV`yeUXr{lH?*Y#!Bxh^#XncL#jolJCT^KJL8oMz%BATDPT|MHw=K0K5FHk!)F|;qx zC)g|ag+J;%!(7_8_Rgdy-ZDNqIVawxJX$tCdMxs1d6Vd0(Ted`;y=gBlRw~XHtF%6 zw*H-=)}g7PP8pA9Rn1%yel7fGxN~rjzm@k*CsW^N_a(1LT#7#*|FGO!{ARRO{4-#` zn0(!-=e^%^rLS>tb7*DI39Ke(Sm*mucf=2lv4;}JqSwWHr`E=5mU_#V#}>u@E~mQ| ze4LG(|G5^)WrJua`URUzVC0(eZI-THsMu)Km6O7B5n15SUL;vsII4t@40t9 zMuIy82<{Xs4#nM}xI=NLh2q7vIFuHrxD?moP~6>}03pd{<=Xc<`G3t*ST4c=2garNk_!erGO8OIX!I6wj*^b^ zV7C8ppLTm)E~m?J+}>EpZ*4>)ud9y@F7O`-W)DtEndN)$9~Z0`&{J)@+1f!v;}k5c z^mp8HE_Oz^--A(p;z{wO^LFsWy6-saJG!a8@tC$WOX&Hud0>+3_==?L54b{?f;qHZ zW@F{1TESk%G2U6y-OSz4HP><5{*%3?a)t<0JtJBB5U3m2A1EBW>W@!(?XMLW54!dH z;L)H*zsP$xSZ^szWjO1&HoFeE|Mnz%e)BHzR`tAh#XDBpL&{aL!q(mN>Pf*o!Jqx< z{UXpII6ahA+hWuK&6=P*R@*pcI~%*+J2l5*`*wA*ve?$qyr-YhE`(YIPy1{8+xcJm zANv2oHXOm7r$QGs)hubtpsZ4xI8;}%>$7{dr?fZLd&={pXR5opYoViry_539_R0+D z3qvIXT?6%l7lUTtOklFM986F5`!m}8=|v~#N|2Y#6*7T%nCKmVt(CDvqfQ9AlkTTvgodJ$pS%JefQj-SMszXM4v% z^$fn`D|#>Oy*6GOADR^G9lESPzydsB*0gm|lGOF~3dFx0_Q_aE8}Z=0H@4~cCqs4gG)7h9m9fa`FCHt)R3dHa11zIr%0ABSDrP{>qA${tL#u)# z0@(v&0&fC+h)h-p*3`P{WsPy>JKF^Hv)yu3ccr+idwYA+d;joM^9*ypauif^Du0S& z_=+CuQO00nk#S33q4ziTbCOM@`h#5zCBAZ$b8?e4*ZgRlGs+kZKr3_(<_iV`>;1L- zfB0>|8KHt&qPExAXM3qsuorc_at7RakWN#)`MlTIy(X?`yI0+$Y!U0g`)oAs8Apw1 zW0BsFh}9`H>pWNzaiX4B4m$D_o|vu1a3hluLxi9VGq0`%`$GAwfGyF#;qTY^o3cLD?bz5NdY^Mh4GFN2S@)!@T+Df!gAj+?F} zo*%vaJ$b!PyfeJ3JY!t5o$bJ)=frpS0Q+{U@kzg@7dKiO#f%k3SFpN^uu9(;Wrzi~ zHEtOtjg!U@JyH7>3Iv~rs)n*_--2609((~a44?7T^op;_2DPYtvVFXBg=?KlbJiqQ z{>=4@vxg&>{fYWg>4AURjc@TEGh`fOM^9ka*D@EI+03%m??!X;iymt%HjZiyj3}*- zv0Q72ub_c`$QZ7tA%kcL*DClN-&=*nOj}PSMU+=3fiw?utW2P)c>Y2ffgu{8V6T1bS_jwVl{aSG1FLoHVCw-N<#zE;?H!h^KtSqFX5F z0VbO9`7B6Y!xl1Yi2p!2zA$A4kL!3B)`Q=!jjwUGwTIQpjo0IQ{Dh0p?tVk_%7?G` zIZ^gM@a+D;GkfB-Essb078>YnGK43IQ{dn>V*|WL`#z7A8i{Y%1y-{ZmcT>X2lJfy zfYl#_zQ2c6OvjT8@cdI~_CwJAYmj}EL0V6&LP6_$a?Dy08Eenl+(e(OiDgJ9KP)vN z_EBNH&~k}$KT{(ULjr-k0$N{LHg15(kz3fUW!=hIkOz7&RuAY zm+;W0n12u*`T;7S`WZHIUh<_9;gtk5-!Rb9dGICN15YTsImyiT{^Yz;7Y9vVRt%fW ztY4wUSHjA^#YvO{6mDMIFy>Jgi>9%y7~YI6&~twx6xVI4^?0d$56PP-SKs`gj1k?Ly39Dpub_bl`C8 zm@QadbGY^t=;V@M#?ye(Zi$spkT^y;{C7Rf<;vVS8P~C%=ag^+of~!5kKnNAU_#~cN6WqD9KyGh#bp|M2f@l#s9^+ya3f)Nwml2 zlC?P2qSc?nBlI4-Tvk>32mYRpRoR+VG_Y*iFrVgFNgnD2g`mgm*hppZ&u7Ia@dq|k zTh>M5pJlazgiU6fPj#%() z@($V((H+7_qVX35SRWVjY7csja(cAV|C3!@1Y-PGpl1;qJ>SnGYPqU1e zUf}~maVu#rnM1IWG_m*gReK+ z=8NH08KbjpiRgm|DhA2=S;3!)e=}ap6xWfX1*{L?KmO!QIB0#v=TIJdxf}Z89aiKO z_IfXCDZbFB*vf?&Syj;>l{#y))(?pa_ND@(Tg=7h5J$9iF}{UasnMYyt(RaF3gU@g z1+R4#&+!Hda+eASS(Tt6HN=jlRY-GcnG)sdX8S6ZTW)g#aq5Y1+gg(feu6Hy{M}rP#1@xX zW#8i&dTqwTOaH;+1IZJP19?1+$iO$UHrim(Hz0N;>xj(eB&~}^G8wFQ4LZB z5|={<>#*Zj;e+{xZ?rldqC9vdDj@N5!GT9oV`zEst~TZRQFx~_BU@zs+OhZxx54R0 z;mitFAt>(;=&C3F09jN1DiUKW6sCS$pmxPexufRkB-B&mcv8;E~p z8F{HDy2~Tusj=OdXIwPG%uM+9-<$b3xn_{Jv`%DIep0q7wbW{=qJFPNsZ*8ioaNg@ zVJP%E<4cPib>PwOVy-6Jt(;NIxTCkyXX;(`{(5!2GM}>X-Dl%BGP!(UA@+!tN+or= z8ezX@e_+qzsN%@!h;YobkGDTk=c*mm4difj6EpA}g+b$)jrRH!G94F&CIlM=W(4X4 zuK4Q&ss)Y)u7{$u(eTApTS%E_U*z<=DtJzKDtQNZ>Uf8_>o_ypJJ>_Euljj&qVCY= z>5H|tMkjpT^{rN-gj!L&P!_2kr60)gd{!6ZhVdZOB5=#U*uTt|sf-3|O1SR9z=ubuML|4U$B;6v!K{=%qa+Y8REhvNs=R@Xb%NOy!=buDpZ zauiUriMPnaw?q`m5i`1N&V+8}+O~@6qPntO$*mk!@+c9+urHW{jTKt`5KxO?!@#fp zp98~#JAz@_8oh9!7n=OiWBX(~4Gr!?t0+bEVlGjt`l2y%b0HKSPgJC$na&ufJM~T2 zFIK3GRzmBdC1~r>jo%t~%;#u8X~klPiDevQBdirOj9-}hlp`~ z;^)5dR9Vk_dZH!YVbuzVM`$v+K*MwaD|6SJON1*4?RUJ4`WeskJNha8qW(qCZ8S7~ zWt}>ao&7yN$QU9=cffee5+BHe97K%zt&&wOuGWBG>!>BwkaB<+R&nLL7%rl)kYYI5 zTM@fEZVq4{qRe~7UsztvjO>Qfa2p}!P}-`J~B%aAxeilOay222XCpT zEN7+MyrB)5yxrNKoT{aqQ6?+pl(R(0-hd|y!)sZR`T)P1b*UKh);M8IH%1u4jIKss zqaR+x8OD6(_P}^UONQ^w;pTobFP7SNP&hsDp?XD6@;FtZZlieDKIIAP6|a0$9utM1 zt+Z7#gEs8T&iqZ}=?RgeN^r|Ic%_`_H6LJ|>|pfEjde(*JH{v8P=*-cbk^%Bk-<91 z%tiQlqljD00b^m=%8A}k(sA)p2qg#n70XW;SjjiyU$I>D1AFL)mVZM3(WJz-%CdU* zc-llTgKCg zI1gZ_JVZDNqNvZ8ru$0tMWMZ{3$Rdx6wrQU^Pu5cDELU%MfC98Q7yuv?3TsWAwK|jH?(Y%tGr7agO0|UtONvod3Jyaoe*-!ZxcspX8%r66R5n0c*798$k zK2N|-b^|RkfU$2P6RZ*VnNMij`O%KQN4LL29^nXVkh|0%y1?jf@yzpNfUPAvR8~f8 zie~?iICl)A?#f8xiT?gzE5}{!Sn;3Hb{k@usv-`QVm^HT+tBV`qVF!lUMq=pm7dt* zav4LQqN2)cwDGIPI&s?Q2o6QDwum3lM$(eU^@!ZH1aMEi zh+GEHXSZ{j3`D=FXY+uvY|iRGqT)ufZM2z5eX1oev%KbgC58;Kp`6jDKu8K9W43F> zGqm~EL`2qFL;^%LqU{M-k||gVr-|PFEjAIWDnON@57=J)RojMX#jnt;Y{6Y z{HaNl^PkXo9^!M4%|b*oMxvR_vTmc_B#IKY%HlV6_%tZTiy&i5Tm6lrhNYP$ksO7IR5nnKiECDj(uFvrv;pYC0NSV%5h^FKpnPy;b!e~3(w! zvD!&yC9&EpBkb0Dybjff4qYdf>LI_j1QM{U?FP1XMv)16JVj)A8N4d1CCciUeXzmn z;-9EUM&BuPT$+A1JgHn(tMt-&fdnJwz7Jn)yWsxTBg# zM7kXUWeqwME}4NP_eRzr0>zykltfSSE_TIfnvu3x6Z8nzZ6@Ang1s-H3=wISaa3FQhuXx+j6M>1bqF5`J{;nk z)4;=46#YTzEEZp=9T5+CpAAF=IjF$N4?Zp~(#)`sf3ep`zm zA9R!zOWlzX_L>01^-D25B--^Dy449DW9s@ z&6-5phdDkut~%qqQJxd-ah~(|>}T3%S}pZ9M6}xZ(hP`fw-(=8C%sL4m;BS0 zqyC!uq2N;Du0Ge2un7^%!xyBTnC?r=?&z4bZDU$T9u7Nc@9M0g2K8wFhrqMI`=s*U zUM2NPUhXTGeDmAxKyGx^PF8v%X$#zMy>r92hF=Z4<}U1ta~HMu6B%r0jekRzLU{uD z1JC@2eYH|r`3+w}Vnbh-6u*B$%2ofoq}J9%W4FGYtjI~;zr2egtAw9Odmv5OG_g^? zMz4t|>FMtI&z{yX+e+4Q`!|PN{sBn~5?lHD5EDz2GBvT9cENb89kJC?nmc;B`?|Wg zTX~9m<~v&22RolAe?x(*j2h;7bDmdddLJZw>a(O_U@j0VROA_B2Gm#jv5=47;bq> zdGEWgsIQ^nb;e|WTp*D0(RV5Nxi6F)5f~pBk)r8i@I)qo=3DHj?);s7$%=6l)&=Y-`xk6uy_gEz#I@;Kx6%Jhw9S#l&ln-19#`v%JpQ2ZH z!%y2$t?aJi%}S2d?#L-=tjMq7_K2q8(cXvlFy$a9j03?eDKq@`z&4um6!H!B?;x+S zgMYDJUp;{C7O!?7`}Dpew|%uMm#dR{7x`aQG_s0lBGgO|H=Wwx;4k_BQO{;Kme^*i z{nd=1M~B(|FeCM1q1a$|&8sQ?2EI9gNFxR7sFdZh7jw1pTy*yepB_~>s!PO*@Fo#z zc!KMo+6$dA+4$t2;;Z0)l2RumSbc4{l7JGrZ?#dx!tUO`U?wF!Ll zFANq68Y!j7pc`r?qV;`M2D?XxuMCU#ZirZ&=6YoAu%qBs)42Z=SB%wqN4;*KMsm@l zgT4>GP03@E4+REm)F#j$=`|d^U0Xn@)^PO=8|hiCL@Ar>8`O1X9&Nc++qkHSz-NDq zp2f;V9&!;|FUK2d9z0Xa5-H!K#3?V7sv?cKG^7V!gyMr|e1^{-NC}M$3=EbsXRCGX zchtMCx)H7@e|X36v=QAR~7?*~>egs+E=hke@5{nW4&o+A1w~DJW3Z#o?K2!#)hTKNHJj1_AMk18 zy0)8$=^g(Xo{tKh)khEO_lhKR8T?M+;_Jl=>N5nIE*dQW*(Z@kN4e}LDny)h;9 z-oM6|b;CW?E;=^5%Xr+j@uI2g0d3woE${ zIv6|<8eq`x5gV_jy}0YWr&!oGvPT^ryC>PT(=krDL}u_RBTOqAj0q@#V}ZfJS43pD zXyvJ!pit*%r?{#1aXeGEDD#wP)urCG4FaKZ*Q{sc(-&y1^|MAa)_NuK-0+2Ac}*Zk z@PufnybxW$rVPcloq)f(Ag649(9fmNKDQZzKn_pR+Zgfs4DwI!YTL|*VxMwS+*7`D zHt{5Q-ny?k?>dXPYP)XQPukjGHFq|?>EDMM_+$KIgD$;^UO`K*Q9D)ShElvrZRM?6 z*^yx1s|?56eoWjEU(Gw(Um;T)fSvjsi0j(Aie`QStZQ@IRdHNBY;UgK!iO?Ke8fVn zK^D?k<5&F6KU=ZH!!w&_u+;__SG61ZALwPH%^sk9C)+M4Gu6Xj))S(Tf-gX|JO&*%od}*&j8hKcjp(jW*9x0^6EUcnSW{`N z0^~EUMIJ@zZsUa!G}4%_%(J#!$|mr-v$4zPsD1I!bQY7ab8Zo9-DUJL1{&AEDla9P zmKE=0f7{PuvWUd9bOA(DYhoECtsQ2P8DYCG#w*W=0_Rocs*~*bSeyQ0Cm9lzMOs@t zdv`-Stk*H}7_;@;dV1p1%S0di3=XB1(uYw_R%(FAiZ7J&S%@5V|Rj z9+($z%|mEDCP04 zP*W0gDiamt&_Hhh`gxuWBcDLjTI5(c=!CW;Ruip#wMpYQR<0c;azF5{0w_E@lrZ@SL+0Bjk&F1Li^sGjG^G9sZ z^|p~>xKcs=S6#1ur!H2qD1Qqd9+4}ikBW)S@KjZW#{PuHI)kl#MTBszt-Kh97xMrZ z?S*7#$gH~(_ypU6axQ^omILJL8CG&6I`sx@kVIR0Q5N6l7O=$MVdwe4{%*q`uo$n+ zE)dA)SbY~2Zz`L8h)HL_kH3yc!g;zhZ3gLfh#Ez!kRf%+-h58nrwWndH>_xGcDtdu z-t?I+uz5>C_bw#Hlpm|}1^4>d3L|Z4~ zF*}$L=vR?Z=XiIhllwC+af^AKQ z|E3IDx9kE`m-YDxkJR^kE4v^Y#3}OP1(6;3EHussbh-_x?=mjORWwzhT5~lZTKuZ>s5k77TPvq z&n#xoh9IF!K;?_6QQHq&@ix((%h-0)*vp$_GK|I|?uTcnD1Lz5?DK5iG6aimAzUGQ zhRa&;72popouoMSoa{pUlrg-;ioC#+bo{gqY|o2Wq>uR4$L}8F@sd^I&-1P9eCZIH!-!=CwDI_n$?PO6cpm%r2kY|~i*^XOQa>@@$*izMRPQ7o ztQ7P3mvsw}XN&A)o~4l%eTYfN5xv^Z(~GhHc4Fj>z|yW{#bghU-uOaua_@cU_yYfb zMGkJq=QtbBVgz2yUicL*;cN9`p~}t`4lMo>XmAb%@#aMmW7yCAQvKX6t1KzuVjBzCyXgwI&EGVf4(m59t@)2n( zyQX|(RR8glj!d;JSi6g%fZ~iHobmp|8pu8YdGUyy!=rhQIOI_BV1DCz9|%XmI&Ngv z54cOgm+~vWS&yHhHJF*~TtArA+GCk!X1tya#ASGW8#x_Qp{HN1wPf3t#3PbZ#E7ZP z=@A_Q`-o9!P(gFGHJTMZN0b2R%x*VkHy=Smh2fLFP{%EEof!cq_WBb7USCE`dnNK=0AY>)>FYIF+^EUA~ z4B#{w2^M)d_q7Mb*@5|tg4X}Q$94#B?4NMZHYDsk^2KYghgmokz}e$Be?pA(9cMvp zP#Sljfsd?443X#DjAaI=;RWKOtKg(vtkW@`c$c+5$eMnDz8~{v8sgeD*vrpw=@TnE zvT`>3keTtxz5DrK{V>|fzR zyg$??ABn`N&AUdx@x|Hw+MF|!Sj~BSyAL`o2_|MHoLr3^Jjb{9@hINOR#o=AmEE)Y^Oi+mSFSihazyA>HByK`J)#(uCC z?RnSl==N)QTVcNc1a+oO)%Xgs7DbueJAPz-(Q|0s4W)O$6L*4rTtuc-M@HTp&Mm-O zt1-i8jP)!&S{X5E#oGt6W--Jk>XG>+V_>u4p*+X~dH&u*{s|%uzu{ZWf&|{f>3f98 zkDocE1E(N+zpWw4IF6Xk8vf;hiie@?2RH?rv))d+3H*pGlsyO*A<>7iVotPt*&{m} zdndb6riB`ZA=!R{+E=rOZ0edA5CpG*{9=k4ss8Fbw=XsfHB>%PR2M-rJi zjyBaDF7-kOFF_Zzg(8+avWGx8c&1gz28rM*$4SzL^~ws0s0}nc44Tv#OM0H-gx;bVr4E08Vt%Ee zIN3|;Hve|QRrz^GQ(|hvIa%%ab{8-|neWz*XJla4moV!JNQ{ikeIGNw&-=^r%S+I`!Bv~lWN!2C^*n7U>y?4`B(P^6pt`r59A4HfjGu6JzAtnf z$6dLRlSQ~nV~^YLZD~eIjd>_OJ5QHgQ)J(rH~8k4F_sjrlc)48K7}I#Po(NZ-*MM_ zyv-w7TiKUP_7CrkjM;=^5qK@XoFtza-FQbtMa$Sp8dy2W0>u^R0-`sLQKPUlqdd0R(l*a!(eE&Ds)^7 z8qdu*$1tlX_^==|Nr$An#JrM-cE}FI*^mLU#(AOF0Hw;#SFf0j%HM-d;>~3!8*$B zWNCS7K{WjASnyIl$hrtp13V1JZst87;nkPSvK&&r4e!s%ND>&c2O4X}3f1Jh{Cq3z zl)^kMijjOn*8c@PEaq7`QzeD8O1?n3kCBlJkb9pQlY-QcS*2y*F^L+z%ZmEInwDZT zuNj>a?kvyqWLB%xbxN>fJDF8l<|40`lIsVq{$CHLXzog2Jr5vnPBY?U)+-Zd@V~tA zYAT-|hdcg49?6bR$Cz1KD847uu@@SZ9Z#FEI*IVdFus+2jUsvHR8FcdJkL)wF%KMe zompf|l@_v|^|e$9_6S*YlvPS(w(F3`hxz=0HL|D57+Eb@g<4E_%*|MfaQFY}Tem=p zbY*qY!b3UXrO&BS(FYwAfp6ckOD~~2+2v~;J8_s<+=o8p%v{i-tjZj~l9hefWo7FS z&-Xx6GMiau{-#AL$ZSa2SE(RZxQNnUWi>9a2T$PMw0swXmH3Dixx#m{_mw=yyqr$b z#*`h!agp#`*(EGG_1eeC-UQ|!%d=&Ns$8jjASFx;@2ru^t!a3ltmQ4MV>{TRbnx{P z-fY4m9_1X8JsRu}a6h z!g_`AO)Ro99luwZnWVoY=3&8uk{Z7-X6gTU!aG0n`5Et$eGs2A!{>aGbnuybRNj`6 z=gS#o;rVG8dpf?0Vnt<#I!VWN*6n}Y^TK$FU^iq{0V!EO@k!&(Ape%Dqi{di z;8ZCgIqqxfleJWu(o**|D`QO0*fO&3Q~_fBWEVYor#w62Q^yeE*`Ij7>^3UBKN9aG zpKS5%TdtB6`HU0eEp!%SHEldY<;p0YCcC!DZhx}pc{r;idtJrwZ5XQ}djiURaWacY zc0U~>k(6d+I_t4cl)?U)C)b0})hl<>_bC2wOsPiuuSIdrk-&j`-UUcw8*-cOO z3yt7U*?llQ-^yOAI`fw6`kJdh@?6;^P>xqpfRrb4tWH)*jz!A22*zi^(^3|sWhb-o zy{x|QnNhv}{~sTe6ULan@DtA%Kc@ap;?yJ$1X(lrZn;mA?gf8Kxg)DGWP&hN?gih;Kc%F745zysWhox(s7=H0bDm9XRC*MDU|?t$eSf1=)L4c4(AT6p4)U zp&83Qv$Dsu>@sb#Iv*LSlyy>54YL2TXG3P59pJYLYnq$=_3|dU!;+R{UrWhZ7Wcnq zoPPfPlFC1l3Jw09%)dVKw;Y)Q?aAJnlE0<2mm_hd(vQ@VBIQVsXIqR#O2Y6|ew4H+;CesnCr2TlBBjok)G-^3 zRX$77ub)pL-XKRHd)`Z4mR&cK7{8S5@@$oJ&dO?(My6!p3JtxvAm^_Nx5`mS?LlTB z-DHPk=h+vWRNKv$cEhhQw0)HW=XmAv~oYf*v| zJs0;?BOWn3)x*>SJ#7I0%U<^5@GiQL; z=d)b1AIxYTqJPiKWU~*x*24G!I%1!E1S$I~6?$ZxF`25I^mL_%)?GT)98(&p_0`u( zMX(jSiJUE?#z+w`ZyE6S9wBOxiFb`68uFS7oXtQ;*8!v6lXba(b&^O8)*fa*^Ec`W zC7Kgh!`Gn9ra~X5>F%Z))%C|(X8n}*No%2(Hp&x^DUSzqDsK!UQa;zQ-7yBl%3*s& zdk6I{SaPSx0%j^B^|Rg^x2b$uinrUrFL%ZY+=@r^Dc0siuup~IjL&8?6%h*KpY2A* z;waONCq6%QAKDNlipL}JhCSX4DlQt7=5R8enqnK~HlKiOuL5?rkhz!WcS9;M6$Bk! z4m3?Ir5OExzS_$=3%EwP+Pd01_c^ZEW7LP_*$gtyX{$o@LJxz7>4`N;-${+%+qO1J z5B0QKT1~4~R4b@4N?w^WM7(E}en;D)J=A(pA0^R@#v|xZUMhvuTgrDtx;Nly%A(%} z6HwUy#b27*$v)(a)MeZe;MnE&|ASu zT0X5zXnknD{>1D+gfo&XfZWvAZmcFM0phZ2K$N~Q9_mYs*2a82kN&-W&lp686ZJ=5I;RwQ&a*f2DmYU~xXO~wPuthR9YoDuZV z>f#Q$%DZp4GC7B;y+tuHX-1h{^sHKxR#DGq{0cI@w)udHo$ZL_&lN?$@1J6qE|LeJ z89C_0G*T}|X7MN^l4?}lpueN|Vk$s^FX`qt02{WE^_e~NQ;WDDSpz8`)>`WwwFP=* zXkZZ8#HZ=o-~(5GkvxHp_PmaR_NMk{bd$R7*yt!`&qHUaerk%+SIDYCV~K3L%_2q> z{hc1G|E?9*Z)tU?bKDxAXiYM4=My)7N_T_I;;XGH6)@{qt<9BWPu(`}ldro3w0%4k znhuz!sLxvn&-fN|pZO75FH3)uPK;+R@}e_QpXwmvZHkNBjq^$poe+KzKY+dsh;GUU zalyp*DH84X9OKkqsFwE0ao90TIcL?UhG{Wd8MB5qCwMuyHCQ=RBUDd&rdOkbU6fK# zO>duJAFftZKEvP7tf^)eI!+bTm+F%YhmokA0$Wy#sNH`=<3*Fndf#e(pYOs?z-`olpPB+PxgJ#AMsjWne939sxZgv8byozkLQ^Y^^8*Qo9 z_9Hn2lNrZY@?uZY3DF_uAjM0WY4EzfU^Zo_j+ln%a5JR-3~G;_Q}&1opcS7HseA?6 zTV{q$VRy0+Ps|LuHly?h5WOuT=Ck5Wk!~mPw5+27=Pf?B20i-#luLdYb0^Dh8ri~i zv8TJ!>5802>n>8UIM>xgff#Qy7;Ek{o)!jnv$S3A)FfEtNHf9rB9g&au z{QxRGXv@VIHP$r;t5Fs#@C@q3b6N#JS@ zuqyw81pghaXBVK*Zy#X@I9BoU=P4l3v;rABi|*02@~u zUwR}Q($$t*Sjf_)L=aEW|6>7Jd@u0u%)!TVhkV~N)*!Kq@e((tw&i}fIX|(njnoR> zO1+``Wyn`kVlYuBJ5kKSfizQB^6D^*I@88a;wS#+RP~m6@QOL!}Ok$mQ?|vd0 zlAma-j5!X&5A}sJa0S`U`>jXj6|zNNbIN={|64@1ga$JD4w-q+K!tBJ9&?JXX8lZ4 z;*4u?PGqnuiv(gQ53Kw~9N4CR6)$JoElz?QVgT{2Gv*{D^nNmxiWBdeg*RZ9~O(rLT(9`eIPj%!_5kKcE1;=iQxROk2*&h2T9lnfHm+5uwIA(8#JQYOod?q(&@$V&#^be{*t75FNmcpJWz?p}I-7 zT+~R~PSxw};OJkGJza)+P`kmBOvW$2%j{*Pp&Cp#qNI($<|k4|x-)f-`*HG&2Vvfb zzrT@z3?G>#tc%7<;)Z#}Xj@P40-fNEsQLY8#Y8HiyGg8mt36}2} zR&tj$fts-sc+Yb537zkq)Y_^>6*31J8r6f?(cI|K2aGl96;n~ZH`hZ?EvyxSN(0I_ zC@f&;W+`%rZqgxX1?PHctGC$4t}h~g;F%eC0$2G(=B(1wXftFw7R z8Ey0zpY=7OIN67TMU)Yv%r@IA{pg8%n8@=Vpt|o{R7^wuWr5oZkzW%jl2Gk)uws2} zr9?Y&2IfnISO=hiNziB+uI1J-G84ej&$LC0 zJ?1n{xT92sTZmSCh~85-hzVUKpXDO&`OVyJHnB8L-qu7z3quiS$R zAyF!mH9|y;s*M62?k#et51RW0+e6VnjO5KGvS2bNb6XHL`^hM*Yxs4iF^r5uo0$_7 z{dwrW8#1~xU2uylX_aZbXS+yN9BNr=aP(E)&_Qvla+zK2FMg&^;aseQ<9Mn+AR(WF zQCvyiqMBwly-^?(%C8S%q{}#G|5eAj8atxw`NUcgM%7V`4xweuSR_+gvz69bi`N<( zcl9v+Cu+IO)K&c-y{T49?`#w_{vy}=wWT9nYA6>~0Vb}Z^MPxtCktI32D`R91CFcq zzZ8WU7!Qpix=TABIvbo7+=C|8gW9#{jUwi3s~}mx>y`n=F3)MjHkEM=r7( zBfp*{SdDtR3sVO8xA{N%MQE1Z(gYVlEuj03jINu`CXQ?NhxWGWRPu;U=+nRzJ_|Jt zKBt1s3vHHB3+tykeZViHx%Vd5`Gj&y8Ke9tsDXwiu}$BmJqfJ<0o+sT8Qc`8q2+|T zXVGi3zx^N2^Y8}YJ-r^P2L0z%J)P~;c%v3uS-nQ^y6KzYNxg~6sIlI)X<4QRB*c116{a*lpNW4ZH=W2=3$T3ubG81yYap^w#v=r1*oc8l7q;-GrRPk(e&vnhB z^4dMeVWmAe&>xKl)bDBe2j=LV^udPIRG!h*b&=Z7QNs0&oQa06`_4_yM~?FLG)iw z4&}t|Tod|EOQBQS0W#X2i~VYU`(FEbY941+pHdrp0=)>_*tWIJ%lbZTl{QmX=qGZR z-8xO3k&j5gL82OYw02})RW!tj*v99n(ErLfuD7J?PHUq&8Nsn!-xb`0X`K@{6ie-H z&+d5d_}h8g`PGrhvBZ8uJ)<|1Ljx6e|=%%O0lG`boVx2YsVLL{|q5(!x`J%gd zo(%7g`V`$`Of-5UB^se0F0i#GBYB_jkc}}xB-%cpd54o}`4gVLj@Bzv*78j;_waWY zEGp??sz=mxApP+)F<9xZd{COG6RDp(hVH!ulpyuIs)E;Yb5CdU81E}Y&4W+IH)EUp z-+V}1t~#EeN48%@OL9RZN+*`eEe)-C^ntNqhs`r1$rBq1Rh1yea38VzK1AZllp|U@ z0gP)+vi`bYOOFLnf{zMK`UZQwlHA(KSQCrTsuRfi!{dvmr2~E?8+ejiJfjMc&qmaz zNDEf9CR*egTy0tKLC(h(namvj!uIWGwkNi87QDEdh~q-=4@>bxRUtZ*8~@lxtQa>L zXPs?wpL}lYBA`!SwXT!b5=bu zUt?(+bfYW-&nII`KH&F#7*{^@SUN2bkFSmGGeW3%0dAt#{Ryt%J1olA_%Sjt>W{>W z4_ReJO*DDg-6W3O#xk~UW?I zlu9HXXzC>rXDA+xA=Df`kN5Hr*4=okgZPBa{R+**PCooPzM(%X`y$xU4pc>Pqm3P8 zACD0KpK3lQ=3=6m9whF11iMmVf17~=qF*RBZBKNzChW=qGECR7`xWs5B;qA&jurZu zJ1dc=+>L5L1L$jVHG~4&Od8Z8YcVXy;2ox^{+A>aqg=V*hTG6iwdt zU~I!D)Q~|TUG46=6Ee^_`#^BYAt71J9JRBnLYb5Bj#tKu{R$t@WUlxL z9lWTmiOf)-hfpmlk@>MClf@+EgOwFOVq04?YF)3R_P$}2MK8E-&Y&(~PO60Tvb8bK z89i)5St!m}b72t9h35cooDU~9ahEANkk z`Wv$AiFL_y*Orwy6UVw=ljD ztWP6oR-y?i5fh1mPxf$TXCg9l2As@S@H6Rb|6y@f$OZo=~I|p7|r`fF|UebuRS1}{5&!^Mr0TN;aQr+8Q6ljObVPK<9xCP zQ%<6fd6EBx!Q%`h^JWO6ti*`+Kux8r%bcZo&??fIx*_l_AE6&YTV@xF9M3~P2U&?^ z2bH~+bLw{!rLo<2@|)qzP6gR>hv#17JV6nylB@gcMpS@D>v zWYSDWw$)@tNvz8{&Vaedrpd@HiMm{m)cnAS>|hVlzyoEOcV^BG8IOAkwckc!?}HzA z5tUkl%={DV%t^+144RNMcIqQ)RT5T;~R$8ZzR;U zfLWd5sc-Qjg}^@HHQ=Wx&*%*9s5WOpd$2~s@kdT0c60>$MmG!a&R;l#uOUNQvKJR^ zB}E>*?|DQ~VHfX-?lfk^QCR&|spVeD`f8pt!$74!L=)@98(VNzxRE6ZoK6FYcva&1 z@w}}(pL?gGzAA85%LsRVC@(D(nvRjDurpCeXtL?qAsJDx0td_ZwCtScgO+`G6;2}) zAF@w(__+%D=`5d5@^cD=)Lnk_0qLB`kBr|&LA7c5zbN!p017L|saKX2{~ikL!OSGe zFDF-hgbuba?%z3MW^*3PHM;;Mq+zAHGx8Oz^k(q!^YP-hMRLcoS0Owecj2{d?9_ZH zen2YCPXkG~goxp0PL4Cs=ta0Qn%TrM-)8)@f-Z(5`8%@?ZO|AiGqU_pnv9m}L{??A zJApS#w7_dV$=JEX0XaGUB!VM>6JJLAWdvVmhH}TH_fq2YB|hX8y3ZqG{}L7PmTSN9 ztwf5dTq*G{)agUMWM%DhqEV)29+~-xN&WdB9zvolB-X|Whx)ibf#=KE?H9)LoTtmY z9*Mg7%9tc3k)BXInfi9zp{I`Re+UnY(Z;8aO2&%6q{e=IteG6GL~6)LcNBL?tVc$u zAQL0Y!!Ak0SWM~@B`!in!zCg~BAgtY3;&CV$1@6v|Bx${f*dpV@?CS+}q7ZaC#TBvdmAR0*stdclaijYzLWZRg0a@!>Dq?0e7kL(g3dT^PZcG zP|9yLRhHM_4R}iMQ09j3=Gu0cRE&gnHzDOaqiLTbN+2_%Dj{`ep<6y-)Qyox*^#mR zvEiN~p`Nn8Ti~E~$a{lX#KJM9m}dr_nTOd*T#B?D;`mM4)V-IOx$L}EA`hfRk(Ixb zke<@Uh=A%taA+1#yX!cEsp`opS=fceIca1j%NU;hNe)bJx7>3mn zB8Jw1-QLZbZ^i0)&JHc-`qAin^P#4T$enx0dWn^J%avvE^c^6I@(C?Q#&z1*s-g9- zhb}Jj-mb{`8L62aRiU`nyyYv^NI#jEs4e<|(I020!&t+e)R{#y=WS6)j)$BIJ*mf3 zn6rKabwkH-0;@c;K6?Qoor*KLIF~0AL&=AIafj-&DMVY|;#2NQO)<*2H^uo*Y7gJZ~GZDZqj3X=SwvntEnUm204fqk+Zq2bxX0a+S zcnkSp===eyJzb;6Upn-VChTW2yVi-5ms&FDUpZ}G=vwgF(PMV zg`htVMzY2eZSbJ!x&;V!Ds=u#oVk1@sqRG>-bl>LQxV^i+V zLPVh)H4O_QZPFl-=fGuHR`}(wp%cWR(UpJ}IB%(pRNpEiYQWX9dQuT+IvQRij~zd# z!WBoz!kvNEKNpMk0&|&$4Y7|XZZ+x(8D>NAKP`R(a%2tmcfl1I}om_VpSrNlv&x0m*F{-Eo+uNq9*DH z`luS{J5PD*TKMWG?#>VOR!1AyX#GsptBJ^t^l)t?ku6#8C@VF3)}V$K2ZiMdJ*B@_6G2t_ADI|8rP zQ;;+#(1fVcjHhM~{Lu|Mi6i^(XZYShACNj&ge8rty@WkF63 zDl}oGNj>Qq8gMj ze)R81be5n>%zV!PPX$jePce6_Gplo;xzj-h(+3z z{OU0Az)Yk%YioKoxPlWxI|B`ZW&H0`W(M0OS%Hh8Eh(psd0I8wZG}o5&SLKW!UlPB zhUZ8l!pDdG8=2j`&(qg&g^HM+jbqlMP>#@Yy=5R;-x%7cMOsVr=XfP=*#;_MVi>*A z8d4WM0`KB9{bfpqV66W@%7~PlNgV=v5~F;TwBo)a`XarfHPzn4e%~|B^DVq%WcrA) z(KVxf2sa{&c{6!#IQJ>nY~4fqjrpPDzE{DL{$j!DK|Ofc8f)C*4B4Yha5b~Pr)p~r zC8K(j?n-H?;{Pac*0-LR%$}rCi7k9R6Gta|gAY^Y;v>!@3OID<{IEmbDN#++)J^jw z+8aGGazR8V?{IflM^EL3IVBJbHV&3eIg?T&rG4N?U~4FiRohglg`dk_#`%-uwBs-P zVfBsZZ8bIa=siPw0`}xaiN%s{`DP^D{gyZR%eO#qTcEU--5hEAHiv{ka{E_tX>%eb6Ck;q$pXf-Qlib(8+nA&;u{~5KxTkpUgwIQ3 zM&*sE5#2XxdQ|tQ)1D*FGHNq1*QgjO7yLQ#Thi>5i@sm|H3Q8IKiH@O&Zf?Zo+aM2 z^iFx;80Y*|EoKhY0>NZ|6JL&`9}|B{JeRN`;aXy0|2qGyz|iDj+H29&p39L=Def&7 zQ6Z*uyrX4V7s$v_UTya+QM7VCb z@4523CpoU;<*I0A)UF2l_Q^l^75{c?)`(4L2 zM>FRYSGe2bF6}zy9Pj?msndB=r_#e<;`{-9e5j!wNvzeNqvCBmtdrEn_H;@aWhz#3 zM{qX{&9`**EUSGEP7b<)R$u}ZbK`=U0^Z<$eVOsjY-Rkd|7fNc=hbT<_9m!v?PXj6 z_d8d}dESwMjwjLcfn{xkA(ur=VH{QZ72FtL$E#C z!#J>N*R&DH!#VVPNYXxpx@g7pS4K4UYnN2(u@v6#jGTFEko^Hp#j#?xGE$vM)#YjI z=}X6J$06{KOYKGM9{O2CirwVbE9Pygrsk#NLtA5uF`f+a`{2#m;!ADJQ^#@2RHtT3 z9Gy~M8w(7>C_((YoEc*%RJ=W9bTcng<+%p2oU!0e@{63x4x(Sz=xv(pxB_oPI2Smk zIUd+k?DOehGRO9q>LZ8nMwxnMB-kl!mwu2Q_uavijG&f(dhr%rXau^_V&fupj<%q6 z&H`UBmeVl?tsyN4vYXUmG4!e0_0abrd+28^LchiebhPEAzH~ju31=p^!}FS+s+rtH zT$h}hJ&Rh@Hl2Q&@mfC6eP6V4x-tfu=G+b%n%^wsDC(|ERIh?7kEf&e8C{7UdOkRBD(Q*nHWg*9 zruyOF{FIUY{K2$Zf}RbeNi$KwUf9{e9dsXY-FD?_ zT`)RyD9D`jtk~#x@op|MR?tHobeX*jC1#PhC7bgce95V zEElyhGlyP>Nr`GN< zsui^XvH7=ANF1?mbpGnJ?1dcN99y8R|0C%vz^pi$E<8PRW$(J-F2RCZ2=4AASa8>1 z`G8=-0|bZQ?i$>JLvRAYCAjZ*7_Y3Qq-opQ_-yO)P|1MUlcU?uox<*#s22L z33Q6-;ZO5-F}_%P?7gNET#{DAw@EK%O;g?*xdXNR7t9Qfxsd~6=0<)93%WmqMMl(! zoZ+f2-Ws)oKN)vqAH{3^PVl|U^k|RVnb7CE>CWc}S6i#4)OEx&+x7YWL4mb_Cwhu8 z$b4=5Y9LMs*CNR}CKu4#qmI7Nzas5oTCMb{fp%tpG0T0$^EA3a?DV+3v0J0R4lnL( zETYVxgRA^+QS_VR?_|CZxjf^d2gc@%ITg{!olRS;^sp}Lk%48t2fiGvo4sZ^D@N|K zM~brI7yVFL(JzIQcX$T}`x@E(b<*GY^C&kWN+p&`{1DSS{I$DM*xj&w?pMl>Mo0f^ z?_c^udm%Pztk^7E+TF0)Q3WGa#*oSW-8^FcW?iwi%RE+7eOqvkKGlrETSzn41snU1 z`imIUx`~{|5%06)h@_UOO@moE6PLMbhINT76?-cFOI($hw;s3JMP@VBqHA8CE>?d3 zK&y*3K4NPt@>=C2`FhCPhSozOJyLu4z@W%pfoz+u`4jbHpO-?G3wtCTWWT-R1=UpwQ& z`$f%(niLV|9;fs+`x@=YIDY}f{LAdFuMOVQ4_n93?YX3<`)>pSdJnU|G0Zn4W!jgP zNkLzjz0qAW;y7HBgvephePR#Cv>F1j za=7z|J;R!87Nl!eypbHp=wIZorjM3+)dE@!l2D_%jg%iK9D>3 zK<{X+l!MH>!Kgr2Z%yA_uQUBfdWyfe8LhcFd3#5$j(8nDH~jCg2Cg;gEvu})(LdFv z_=^PoHj0XWo&CcXMja8eX#!m{_x!MB;hQ3(qF+Sb@jQ04uuteu0$2T0d=veH^onwX)*NNZ zxQHy_Q$4fX>*3Z^b7WF)+V$X~cMpv5{}fb=X4X!7nUx_}%hw=vY3jN39=;oa*G3CD zP<`u~;aM2DGiqkk;RrLVFMh!#E6TX+pXtr&@2JnSD>}Y&dE8#tBv(IJ89CjRT~FvT zMux%aX$B29s$+5b`(Q6)jyViQOH#Tw<=@n^>AM1h&1EnY&N%M7dVAJK6pYFp6&6w5 zJw*LMHi!EV1?%dzHIwtNuBfYRM~`oX^Oz%9Yw4)vn4y(XC)BO#_Z*0_g+Uyt}R;#m08u-SC>ixA_fL|9BWq>^Z_y_JSN zTdc(+7)LF`LdRamXosqKKnK3FHk!SOkKE=){Y~)iU}pUxeG7jKt_b`V*bo$Ed-$y1 zh%WS6YvG*dYUkeTwq2!Not&i|-)r^h_B;#ZXao$_m7pnWsL|-GUV!U0K^?8m7HQ-n zb4WiUziDJO#_DIO2dJd))Zf$BsL& z(pZcjhtO9%P}i$FL4}sm+vy{-@ft4YFUlWkPe)HJfcn`CF&d@G{Hi1~(~wiUC7Js> zbnKc7N6<&#tOl|X+E!id?Np(7WnSwbeYK8+xb*TdDy^gKoa7OIL;=5pt*GClqI(XX zWRm)Wb_Z_Ccx5(9XlK#)`eaWMyObwt9`TiwWGBWe9YneuV{fs#ixc1@J<#^6V-J;^ z?4OylLNF2Y!}d_&PF$12dHQT*U#pO_JO{FZ5)v4G4s`>$@lEzNR;7@8_Y& zpw^++S{6L1g<`rqq4=%k0?Z7YvYOnhH0BwvQFpT!t>m(BrRdoZSfV5@r>uV0=coBA`@_gQAhE!x1A+Cz>(Ay+UMK6Y&}RC+<4W57X+()0Ci zIa2)rP0~|j2_7r4vZ44OTdSzyffNq1S_uz(U?~i*W}w{VP-$OFZ{o$mO@?;_`(`fc z8gqn&U-?qb5-A|Z1F4l*FIFg1!CueF6Lwxu(P}V$LtS-7svdi&`qVm&#r&R3eM33I zo-SL7Ow=(4F)pU^2N7&X#x_b#SGEaHtiP$R# znF_iJsSo58`0}Z;J&531`y(|75rS@bc28;ux~PWrD?FIm%rm=7XyDofKx>OAwNY80 zEDysnS*;8dhinB_!ByT@9#Mw<*#&mMC2Add*#B7nif;B8^_C0=seB_}hz(X3YLxEV zWkh$zwv7(JsJX}@+7IlzDpVp|;!2j%N)}Oj!bP#+csY3!r6(%YrPgp_EqBUyS(Fobi=-BBEP2_RH9lG+%yt|zYAD+AA7P@ z7(01SbYa&eioW&<(G~phkVp_k$Zb-%S!+_Ro)8RaZ?-4S_8ZDiFJH__#;frU$C_kAGS zI*W6=fY=S|sGs}}l>QsxC&Raz{NYpi6YRFHu}QgMKyIW$X(fz@o3I+|DkIbu0(KEq z6Q$V)Bjgz?1@_!k>X@nvgL5sTQUE^cMCFM34$Qm*_pc*bqZnHci`Ue4$OG)O+w@W! z&RTgcj>0Nh4fDVfYsEnn|3fMwUD2fa7F=Jk8ri$ZYx!UaHKmsBI#xcK-YVDWx%!-) zbea|V1@yHMZ|P@cuWXM+s4Ys6;cL!Q6jNDU%4TvWH|^E(sy)>D4O~C46qX=bstKemY^u?;f`Co|b(a@Hj0>7dRzxxBY zbrZ2&EE7545gORZBHaHaIQ(0ysk{Ut@*P>A^3-A!<_uT}|MCb~#A0M8cfp$&2zw&Y z9u8x;Fx5UqVR*EnDj`-~OhsHz>T3T&3pI_rUv1`NIlkr&IL||{92uyJ$qvh7n+(7h zy<{B+`JZ8~H|`mG%)e0?&u%TY{Ek;H_O1aT?;9I<8QABq z9za7GuX%y;PWM=_gZH?3N8!Y7r>}O;9tU189E>%k% z=!;DMG5O<{d8r-rjdp&=B}c#Tjj`u5w#c+JaY5{{sIaJ0p6?w$8`J&O0-NbA+}@Yw z`$M;^6gA3u!uc(@=fLpmVQ1YAZ8?mih1Q>X{=mFIT5yV4+WKrnSfSms4sLHrH4LJ} zN@Hp2iR4|WOMN3#jnA(?CMP$yGCLYM=R0#nbjr{+d--hl5|%{{iEJLZ+5Npdo;EGz zRJzyS(RVGap7($;%DFq@Wq22Ny|9XrF;VgEGj?@zzFEjh)8l>By#EAy(97*lI^nh; zcj0!_P#eR|>nrx#m3@y=%B4I=zv^9`Jm>S;&)tHtT3>f7cQ#M0xZ7C{Wbd4D0lMzJ zA_DFh<#2k{q+_XLd<%W&)Asr&gA0F6j$mNqsqhmK&pfg2tXctUr4fWJJ}2;x&mZ^; zG=W~IWC9q)K zTcZ5w)>Uk2JZzO>RC7KNKg%Df;q5LxcB0>tzBO%_Px`~sXC{|Sy<+WfOn0wxXNwpV zzc2H}OuJ&kqGpGOd9tfD^^s|ZQoc@q;LVrjPV1qkX`{oxgx}_#8KQ?omk;Zt)G!mQ zch(X;;A`%C7i_>D>0uo+ugGc2E|9z#)^T$n72TWs8+`TCyZKIfOQ%opzVTO9eA-U; zm9V@~6XVY&`jJqxBVT#0xgwQV{c(DZ^cU$BQV*oJ@lUgIXboK-!>3358Mz{2diV_Y zP_bQ(p+?|X@MR!ZFdvl?UUb&mTKnKS(K+HNw2%ts~cl zyU0^~r5;e;6JOsC9u2k)ehsE^M6YO$vUbpO>`!|*R`WsR&@dIo#Q;7;Uh?});}>A5 zYYP9~#f z5Q9%wbJM5rxmbWV9jaZgh}XUWr2Gfiq3^lMcCIy%`seEK3KL{OnUyYRI>=#ZSx8nT zA94ULXcj8X7nARF;my~Fy}h52XQ3xwZ#w906KD9kEFK9j9hENA5pOQOQ)x1|f8ljB zCi0-yCFAUY?!wn(IA72s^a}CnCb^bw)NADy?r?!|Jmf2hv#K0*-ZNoiKPKuaN8~Vu z_~9bVLJgLG1pZS2kw@eb(Olm`SK%n^zn<{dYU9mD6S2_S6mCeUf9gbLW-?67&YYU9 zxpyPfh?~O#`H8Df;S-yQ3;$v6zQ7;I$5~gK?DYV$2E&LKX7JxAVz7aH_2cS|iO4Dv z*W~BF1eiM^{^wc77*fU9!3aMwDg^~9Rwv_@GCLWKx2D8_k zXKD{0sV{fx^WPl@@qItynCAGjB^gUd-zKC_=jHT!2{-68r|?#;w;qpSF{7VN+!0dk z+`wH966cqTbZ5L=Bcz^shC3dE&v$}&`5Lk6d3Z->`Iqb5xq4i~K}uA^oj*B9M?eUWk(y(sK%N^q%n*(!_fB z-`6AV^YTB2T!^do{~Awz{tRi;guX(0IFkE^G`2G1&xZ74@^bYY%v`4bxO{OuSL}Zr zwrHL%5{6qyrzWH%_7YxENSi9eiNxE7UG#{bo+39in^<=T5p_8f;M>7p&&Lx#hMAmI zNuu+>3M-K=kPVc2&LZyKjy%+dPY}zrqH2uHZVWf)(bue^z0y2n93^zRrA`;$Q|nn% zxhXo)%ku+OGTW4JwW6qOkAxXL9S+g;7HHX$)iKN3~A;qWeQM*zu^`$~A$>spLNvYv zj^A&@#brSMyAqKfB3AAV>*^#-qXoRHQp9!D?T>ORyQeeN?ta-7oXiD!(STXa$Et2b zKii#DuXtcJ%>)DM3Nv@8T>)-NUa^Q?zDvmlHW!cS%{Pe%bsg-Mg+ziC=?hf>4(1W! zjc$DZ0hHsa#NL32^kGbg*(ay?#6vp(O0t-0zux$q=kXOLa^+s^pp`_szwlc=DljVW z^R7hy&DnK|h-U{!5Z5^1oqdr*Sb5*EufOA-P3cQHncY)-&g)AuXd=hW$U*hj0tneJd z0duzu)?y%*FC%mGGrM&^HX@`A7*Ym&2@kCV>_G4z-s3Ylm1ipBC3Q*}^mZxgK{;CY~v@`s~2$2&`=5?(9 zN8aJToHIJBC==uQ`adps4q~YTtPu}!dp3~3cUXghMA&n&${9EjD#BB~gpGX%H}obR z)H7DiFk-IdjJ6ZMc5b3{ptBr*h6lMfg=puV=DCa~~IMO+ojWX2kJ>cYuA~MYj3Oa~Ux59!BL??Ee zeUfu;FC4El=IJ(1+!)-sC-(k#*70P1wuhC_h^THqZ|WB8!e2l_Yw^xH^7Pwbd+mW4 zFpYKDmO2|hr`QDQhTiZmP08AyfOEJB##?1pM+r{9nIM5rSzj~B`hSKsIFlZc;jG(Z z@&fPV6SHf>e-B|&9jNFDRj@2zj6318#ll+)sa%%k4A%L1MymV5L-%8(KCDGW>OFpD zg@>xWEvh>bKq;!A1m2c;zrh>s!zo&mb#RIG7)jmxE!J&AEIK@5>~ltDpbjjwY^fB9;odHO#?NG$0;J^xuihgY+!u40<$* zU3!S?w*-UTg%6e@_k#Q$VgD*rua)6^+{?I@p~pcF7-sqwcFMsFd;*PKP0pnZRv^US zO=LCRXU}bBXT@{E7sRTiu$E@>2?ajkX=XYPc9R}-*cu&d>Hv(*x3K?4Vxtu9?q)1` zITb$PFI44f8&Df=hNTawLJ{hJ-8g- z5e-tRS(aj%XYii7;bGMy#vRX&9D;Ay1573hGaQe%){?7!#^RiSL;VnoS{)AHxBP1c zW+n-%wHcfEnX{!fEBY*d`^1=Daw_fM6dKIcW0;9Q+4b?P>W&0>*8Ti zL&v(+u#irCp1gQ}p~@Z`{Idl1@IB{J7`sj~rvB&x?Po4RZ{RJf*T*Wafrqpci}e_L zSs9D+3wO(pk6l@ep~`Lsyz9Zdq4Drhw^0q73{JO}h^jH;8O=#BmtENlM&HtqDi6=y zAHS(1&-XjCGlm_$509ZU>u(oh8BEREYP_EBxcepEP^ce7YbhzvS^w!Y*`UEc6Mkafw>l*F+V2h>?~PALL~9 z<^In*4rz`)XBC{nxBrXTIfEt0i=Ax7ikO8Z{R59~Bp&2GR_PkztF`!2XwAUfpT~L% zRcU^K`&}1%*$clsoP5N&5c8IKTtMz>KWAPB)^-WjYkw?0wTzr@vzVvh*x&hBtTU{; z4XkoEv%i8>`I_I)g?;VE(}x(rW$^F8q?pwaoDsKKMP-?z!}tIhIoXSVtaQScaC06+ zq0-ZpXIVmBL?t-gUJ%0U?2Fo1iOQT4dGN|YS+*{$q(M{*w!p@uGTwja2BZ*ot>!%^ z^3HcMuieOb64}{0F(|tD#ET`ATGXFarh9N7_W5wEgqN&A3|?1;5HS)=M!S^>a%1P{~dGu@QMm`kX z0M6+uf*Jy5Zw#yDq>`6za}i=RCz_x4keSnXJNxH3{zpimoK;FSLw@4oBb=KdPjV2o zEPrv0)y(K8tEIKt`UV_fwzbnrrsr)UNc#$6;Ys+3-N*^~ipzqSNqM_BTi94UK5?m9^ix zXBDQ~+$3X{|Ee#^H!^t3cx!$I&v&ko$u8_H5xyj9c=XJuRgvc++J}4Gy|lmV?dD>m zIw;XHdQcsudZLcj#C6y0L-B4r{OI!5JTuu?!`EaJ)R2?>qjFI^=43u=PcfV7iGjw! zoW?s7RUf(4i1Cl{#`#Md-KjgSZk7*z4CJ%wJMTqA#GZ?p7gas7Smgc4b>Z1vC@bni z0@1-YMoWiDDBv#MJV^^ zh1=06XpOR}$YOGm)r&r_%TiaQ6%RPjtI2GZ^jA$EWVCnWik+OeH-2|a+sMYzbz&C9 zboT62^g!M8mfolSZbm0#tMRk0S~*2c=gIK$o_Fp_4g-9sK5w>-yl;FHoadh&>}R%D zmTLpG=>iJ}PqQVy;4LzF9jwAeCjaZ?(qEEOlKgAXDy-&zoqFDnVoFSvi~}=%jz1H1 zJ6gnDjgOD|r1j7brgcvJl3p;FSHBx{2GaDOq{}%ua!r&kBF^47UWC5*?J|TT~+6-^0z<@w=|6}iUUs0=ob7)l0nEyq#a;;MT zR8MFR9FN5^^R++O+rocE-(rROa972yXP{H#eXR+&*(p4ZBQlqf-&ZubadNxV>b@A? zx%B!e^V60X)tz}`a>wO~H)GX=0~u~)T$tDV`IiebxfF_Wpd6**($|L$1V2aoOUcqH}rv6`PHF{{G%s=~2mH;eOA0PZsx7?Y`WEepYTn z3HJ5gPn(-|!e0Pukfu~n2RM(ryLn>V#kC3WbJk)PubR7pcLF7Y)%6E@S>vEl!Q3DZ z;Om*h_7CvKr(jc`D?f=Iq763YYbsDSa}I39D>;d0wF3V{gO&75_{ooji)BRW33zPl zKsATrj~wMZE6R!0gxc?Y^wMrkU(5_59WQqh9zuP5kEeJct?^Jkp*owF6X=k2+)Ael zqJf_5uks}-BduU;Pr;MDfJZLz>=XID7Gw;^5gGI+4h{8aEP?Of;nc*4&@ z%HE->;ZP?5N(6|j1ipGmA3QX!ka~0u?v;oi6RNNFFhd3TSs}g;y{Tw?{wzer;UKo3 zc_xF^=7LYKRz|29$-5??M)FAZ<#P{ZQM;pTiPzDVx`dEUMKV=>FQQpV%DyHO;?_nb}!1uibUu!F$eJd)l z7sw6Bo+vPk$A9c0_gJ^(E_4zLGq0D(_|K*LU?J*0LtQ*jHB`RGGkyjJdR%q@F}MyU zTtprsw*MN=#}xa8T!SZYoLu32yv^6_!#Xk}o_j4pzZL2}P&OwczMI*b#ECi{uF_;{ z7!i4>wr&{JkRR<_>M(d>L-5lR+1~?g4Q-^~u?5}nwtfZ`e2Bu+Qhdcd;xO27MO3*q zDy8A!)t05L?$*z8DDmt?ytsYxjQEUJRY*;|8<9p0Iu~o)r91vUd{-i#(K0*tIgJ1Q z6yJ8Ha!1UB3HU$i4<``s)?n4OV|8>U;;zA7KSE>@NqjI3zpoCfvLCe_#o3Xuc!~?q z_gH5CP8O*$>#M%ls18$~+LPraGN;$T;t#@K$;mqEV-JMI8mfl<4$nVEbR`x@#scIJ z@8N2}TVn-1m!t4M%d@Ui@F{&*uvWx=uZVOXGH>hbu4KBFvmWn*{kCOi4;R0Qa!eYMxKAOa$BIQsdSJ{ zt$gw-dPdLi#$(}%N^qcMuq67*l~gIug`?tQ<|Z)vLH65qYH2zvzmfNU0fKxAlr%qU zs69PX2f%FoTmC_0e1&*M^2{N-yIZMC{!LjwpzHG%E1&&Vtk=3YZaTWt zHGDkGR#5fV|wuJ_Mq$ZMtrT=T46^nEw|c5y+r+A9avhbxy{&Xq#9L>_WDh| zlIfB6Q&#i;CrKl{?^!U_jERhToOGn>Zgct;VGVyo^aP_drt5{puB$D z3UwfiwKr z%sVoeLBHi6m9i}5l{dFFP!v?Zs81Z#!oQDR8S`7@FYb=mrc?d~;N4r`A;=wCrk^^(B~-apd*@SE0e zR{21-~y1)*ePD|4sioZ=TfOzt~Bg z(|Y+|`DzAzc0esZNu~-dfw>nbccpEA{h^ zbKy_I-?^u0rPT-2r0x;D71PWw=aY$BY}WK=NpG6E(t9fqCtIK`KFG@EE%WIs+DlAJ zwUwpO*W=$MB*)H=Jr=Vz_C{0-M|m?kwcqFA$yI&b?H6vt(<-94rItupd&E2ds8y$jrt6Z$&Q)qN}CQdI5e7oLe)Z!^^!@BdaW zBj!3^y4~(6T3s~(oCDPb@m`JBhNySVv;Ib@`;vF1&G+B4I*5XfT}r&sFs;;w{qLK9 z%HU8IL*K*fZ;^C5Z{h;Bko%&}=iL^c5nZ{7Fn!QV}<(rV2HEC4( zk-z~*{fL%vza<=qsS}eBzRdHlYm|e&?MB|fwzRwHH~oIu+ubDURqRjEt2}MgOXe;( zMoqno0^i!X9izi`p}A=|KC0L33i2d6h`Zz`YDQ}K|4qx2w#)mKkyrWRxZ)^aFAF^T z()q)(kFjYFtuf)>#$8J6mUuO$Rn!Kmy4Jh@=WHN1`{$(O|583RMn9o#kFw(4#;%Ik zr!}%(>EENYyOJuj9s0>&QgEf!P8%9FJUn~EVAm?8n(?ErnRgCcllH-P@H7Bjf(|`B23f{1DxNArK z6O$H`DdLdhv25VqmRdh~VDdt5Lu;L*PWXbT4G}p#UdKFpx_K*Dh8mYL=;anSR_jId zW9A-tLv(aha|}`}{c`H%PeVVpN}Az6rge&1m#{Zu%Y-K}-6Fb#&2t8|v36~}nRj1u z)0F+*f!0)4o9JP2D`JBYg&pn9zP=`@OHva=OF=1Eq)QAZ8Ic;Pakh_3&)hUi znS|c1$Hx4WYhNBEZ}HwW>XN^zATL>65s(Z}scJ^1%^-!U13K zsd+*<;QSJnC!%b`5zjeSL&rGrt^L_*ZXPrG8CA_2)=TA}*537k{nyO-KXolgR72Bc zG%*tNF9ApJWN?CYR=C{b>3%_i-+e|)mSfF8uvPGR;AYStOx7QoBV|32RV(et=P00c zqblTyHQp>>&NWw=n=Ge%MSUts)^4 zQAcmJmz~qB6`V!wP*80EcG?mC>p(JXQ^>~cz<139tEUsy zLYdUfCP%XgP-<@++0t*#s;AC^{A&S zgx}Q?f9H_spmw4fr8Hjrb<`8)AO zc+1sMg6@XC-b8!1)yQ}o{K42@*~%Ktr=@Bqw4PccZ9Bau9?139LUSOxq!s8Zze3VK zQ(2;>WFPXrl`BT|UN&YoAgi}s=d zeYF)Bu6ObB%i0-1QVYQ{?nvfg0$HN*#MkviFYyar{LkQ}MaksuqjIMh5xH0S22cAH zj9gd>WB`8z#cxIQ@f=U^75j9Tyk>~^V}s_eAfxu4-@HVQ>K1h*lgO@Zm)ot~)>k3k0ue|HJVqT1HiCMJ;&Oxh z7oOr}qLf-zZfbBNwJYRJf0cj3>zk)s#zWj-C7~SIP3$DwJym?AJ=PLc`q)S`!H5-p zkxuKmwNe?xTRI|^f+JT^qg9_>!}`T+WnE*%4Wpj4jn#@uiZ<#SWeXa*P3VKsOl+~M zfu=r#V{wjnFpQ}Qx6U0Zp1q>6hb76rD}P# zlu*f!lvC2=eRG^q(<~4B`wuyfN-D+P2G4j5wau4dw-+W0vspHj8{o^|5>-T1J04D^ zfZMeTuJmEqQ8}ny(^@#DX^&M^E3CCvx01>K8WjExS+X`LFK0s8ccM02JqnloH#4{K zmEKqH2RrDIwOV$ODD%@RC8VvIU0yTmGdKP0P1YkrGZ)DnN*z>r4%m2%&JOOZuEN?1 z@u!-ub=Nv8YphM?L89ByVmPtQc94O+yq!kMHR05LRl5?~J`lB-smyeF$uBagC6#1z zkeP|#4U7BK#MIMY~P}$s=K|w z)b)C1OX9n+=H;MEuVwzvinA{0RrG)vE`Folt-7*YmJnxDq3xE-%-Z%o?Y%qRwIBVH zBv-uWsr#L}+bUpHB7=U^I;ii{zqK+cE7V@#7*kZ;N!CEk2v_kVIjmo)Mo+Y=D)HJD z)HTl$_5NgMu@)I8tt7d?iq%^N#sq&i$%AUgwXYq|lq{CtxMbAF_O>#+ni0wet%f_N zr>)2D&gJ%mt#SRKEtY4APxhO)=na)(EwOd=Ara14HJw=Lq1{d1GKW~_h+C4ZadN0I zwKv)TxcHOkBNK1;wr&Ow1acaw@KiRNFM|7x%gPhjVee(Em6O!ilwc{NGkmZy^1RVd z%=es)xfYq<)mE$PI^mh(eq!GbbPnv49>-%f+ul|-6`~6xMqA*o};Qh&1!1y zkSca$F*|)Oyt0GTgvHBA)NN(9Zx~he-ufo1Gs^BejA{C7>zeXL&8O51Dn742t9c4s zyDaBcLwmRD_+HlE>*|GD0UHw-_aT{Zp*+%h_dlG-49jCtHTEm}ApYSru&Rz>>` zNMczz!x~Ig%VhZcgOq>8P4SEUgVob226C}Rt~7TWxzJ9XX5TXV>N8Ecwu;HJweB>h zTMzVKd@Is!1#a4d)E9P~`9VfSR8I)TE_6Lp^LqXlJuCbN8RZ`qEGWi0=}4fLH~uFU zxo0|a+aA4$SzA4>J+OVc$807RI?9NB)==tM_NtwTj(V7N(2YHBuQR_lx5{T!h5u`q zMqM~4o6W=e3-c@WjQWc)CcUO_sD4J~G|LCJ1qNCdUAH6bs6AnwJaJJg;Zq`x!Os zp5Q=vsMV$4xLBb!*T$$j#67jEIiP z%5Ydf&(R2~Ol3e#v_MCaH){u<;SZTZRsp9dLI<}s{Mii5^bmG2Ke*8fa@1kyReuHl z<}Xm%98{a+QA$wF+nf{aAG?iONu_hFtgU3jI~hV2f1dI)btV6BYOcix*$$pN0HnDN zr{-SJ$T(1*WgxsR_$hyYdK7{?F&1^$zGT?Xqt%&}tngwiWPccak#MG_JSQD5v(_)1)EIHx)=!D1<>jcOXd_O^I^tvg#7pt^6CHINpCTy>T2$K91r6l zHasK9Xe#G4a|4oJj^|Oy?l;FT%gWDlkjJkBf*XfYXj9lHU-M@p5WcG9x)l)ST42nN zv63PEZ=E}bSSg`S-&a9t|01In>fQN~Q{pM-`wjjU;vk;^OZLMP`^cx?;t^&;Ka9RC z|DngB9dRYPi@}PK<<5*r|)53 z7h{!=;;dZHQ}q^uS-Gv`O{y5P;V<6@*&K@2vtQm&URo8YJ#Ru4=qIZeK3gAk75m}7 zq|>7MO#Wc!lOL3t0(P3x)*2~Lq7%zO>wX4>o1{)70=;1!peq?(t@zCzs74B(7zy`% z2%N6~^=^~!vByzE@SW((8hl_UiScS(^$=L{L|ck$;I!{$BQg%zP*I%2zHZNI>dX!> z@c)J|=DpbJB1)uKA`?N(`@*=HA-lnFQbabYiTm-cI)l?~W;YJ73yYGVc8g(`d&m-u z1^ezwom^(o44y$Mn)C}{JWPkZGMxI}_f&FbP!7mrtOY-uvodg7@nXeW=Dd+SOl@y> ze)9?y-%>uqA9jdgptJP!rP~)#IXZaP!I_JJO=p*XsEcGh^`-rboGyA<&(wdcEaE80 zY@)hURuY4x6z#xh_G1ZWp{BTtdZ5Olx|||v$)f6ZSjt;LwVm2L>A@rS$?@tnbGnvd zOi?-G1=$tZS6ygL)h?LBwF>4zwYFu6e)en`sb#kEJL1V|pN40tsF@|1c-d4fqgJ#n z`PBMV+!1h1@!#um#%)%n$kuqTadu|4y_v2)u(QFim}I7lOR&}6f=dq|6Vn6r@pQO- z7kHjarmD@gy!KP;vr<$oN|d|AnCv>%0zRq>XP}L zujC9o!!~l2_JcKBsc*fsFKItoVWPLS!Jed@k+s!TW+O6ek?L*b4`QA?b~iN&^f{kI zag3jC!Uku6NBokt%l@Szc_CS^aY{jX5-j>5b^B}4OmA;xRFAC3=6#2;YOlf+Eeq#rg8Y&GZa=~$9w{zb?a?%P zWW7@>6UlUdJshUaCz8Bxy`jRiq;g6uG6xHr?9Np30T<veaFd|#jZ|vzZgBtvRPlN7M7yC-Prm~_EE2>dF@On4nCxl z&j;Hw8_5WK;N8sX7x}_2N{7kTw$F;Ozoj?HDeuw`T5Nq|H&>q#E%l-n$W8CP%5?av3idHUtw3kE zrUuC8A+ZJ~PZm`0bo5T2 zYIVgyx=U`fVLzy!?Gjczok~sqfWq2aHxxjdrQa! z#i8CMIzK8?t(|s$wXXQg4i3t%I4>4crCtOsT6Lsc`ao|AIP3;eGTb17Cqo6XI3c(DtVB9fDJKKYV4 zoQD~SmTS<>pc1`jzqM8Vt%ew+{wOBc9%9s&?2Qk24BJ2(a*}Hu1Gg)S*aJ_j8~No# ze3vq)XwHB~Secx9sL%RW)PYwZ<5n0ir2#hk8Jxf*-riVtYi}wc%CQHwC{@Yl7gTcL zD=p*+8jB71N~w5$CCO?Y#XBg34+5i!^WY6$K~BzV2Q$_ln}3I>KBUwzf&Bj#n1&Cz z$7XV-4fxHeAtl&Q_2YlKd9&U#C8%_cf><@K(_fua+h_;4!XG4G%}_u zun?=@;2uGVzb|X$C$OYsd4f}QIMy~`-LdLY>*XVJc3HLqH`!^WS-a(I{IE{o6^1=b zZRkAgs_VMq*sQ(P@;Uz2x~WT;+kll1t-@_)Yx=)>c)}O*7xI@MM18frfb}mon8$-p z{f&dQ?GDbT?i{X`T2FPF7VXeQ1ADMF2wk>yoX6d%V;TnnameZe^Dvuet{kw^^-969 z0k8i`ptX@t{w7PAC-e>So%?0XAF-RmTRN6%gTiV=zV!su#ilU&n=j4#dhK8~qcHno z6c%o)-Pqv_Tj$CkTAE*s9kQ(Av)%+Md-r?y1z*VTKnL16JkG(+y3QXRDQZhm&i=~U zYmBCgaAj-3f9$wB=q>yVVmA_1zM=FQidH|N)39EYQsdQh`0>Ly#kb;5FEsP$rvur7 z*YzbZWD3Evyr|}Iwso%v+Y+|RJ=5iLRMNu4Mxx8d#vJ3U(b{xc+TXSsC^hNsL=|oNJ{!_A`)+4ODXQ?C1 z&ShP*{{cbzLzn0*4Y5C=3)&H1^0U2K?WEljojD^**uS#o8rvVxGP(d_*j;3xH^_0b zwZ7S(!QWI*vqmUeM4C3;{VL*k)RTzWp3LsL&P(b(c>&H{(Elc|Mt^5i#c$fF4R=0p zE^%&k+z^KOfDF|OBO~gM+4MO<)0*dK;+g7xpoZa*r7BB>(|)dd1C5MR%3bZe+8JfR zJN8R0oAa5NWtBGnLM7x4r{PalCi9T~Ah5;XCMb;^;5K#5YgR`!#oZucL&SryXRi8G zp%3zm(}o#C{cZHkSg1bc6g}E1tCb8Z6t>clK~#eMcwDrz8|wqT(^6-7qfk@0sx?)f z$ZKl0@O+W$UG=Oi!FuLpcq{kx41s9y<>>7YfbnJhAH#ymTNIzxF% z2c`sZQoSZ>fT%7f=ln{}r;BrVV1_Y*Sm>3#Pb9eWMHGk};d$(8>mIBu4(elu1D2j~;+U36Q%rS?VZsf}6=tSw;Q zvfdfLo0(vF%%%tB6z(uc{fzJ4j4FgI=&J0&X4SV}S>Nifd`G-L1pG!dYnXY-Tp$WM zcfbk#-F?tgFuZrzYUgH$RP!sltnbi_{ABI2;_QOzZMwS6P?xE1Q3coyR^N(_W5zURdXL#LCUpzljDSQS@jGdwimd)>8vVgRSsi{KO^;)dTK5p0x1N^bcI^ zsNwuotE=obo&*-?P0j6AG8y#0Y^hyz_H|5D3&F>FDS!0a{#|-3+7uO0mmMgYxEeVR zIf@XY-VwPSOGTtLGdR{PAr7IgbkPi=EwW#$iiX4s`BupSXW%3(+6nkf4eeJ(nc#@v zbNcF?Gscrat|`j8#=3So61m^y@TuXY+&9HmF+dyZn61pAr(*`$1JtfK9NLOX7xki+ zO>Hi}F?XAXPzcR$+z)mOz7D)KUn;w>M30nv>Jirl=Pl(T9I@-Nt~_BiG9|u8Vf+|6 z94ZGzeUV3*DXY+HY$;Vv8?1WNv|JS>#B*Y)L}JwvB1X)GIX_SCwqr$St2dpZ8`0l% zjBI3Kvbbv0JsS?7(_W(Vslv$x(@&t?VLnfvKZ{a*dvk>FTu zC(xDgm6>LxP~Sbn_*1dz{O+b7d89*gX3#F#S*eirQMp`+zI(ak*UCxM5te`)UsG$T zel##P!1Eu=JFFqg;(r!Gsi8D`y(ap2L#(S-8D)oKr?a}VjiaAqmFrlT;cltDpkwlN z_y7gD_H@)ddT5!{0-)euk>!XK)vbVW+AM;SS_#Vvj`BxaXnw(i8AIR74UXTO(dt_m z3G^!=yHeM9s5eB7*$)pdzfwuOQHNp$qh()NhI6*0JS}ZvSq(p@FCM@NKG8;Tky!yF zpx4l5>p?Jq40Cn6m>g#QgyQ43u6^z#*Cgk8*S)Z*VecG!m3`Jk@X{+rA9_}fGwUi< zQ5!SGziOQ0cdb0w-F)+svC8P?yP4kEzg#wR^l{F0I9z8vl{{gt?)Dp_POzEL+nAvL zs!MaWGE=)lNAioR6D8905R1nQnD4FbGR4eoEhIjEL`PB^A)MR4#WN*F?bYyaW>&?{NLQf0Xcmf<24NAjsc{0N`? zA^a@U+F}isb;xL>g8h$DdeFzbt60xDS^`#5MYP14psxE)|Add9MYfi4T4Y#Fo z&Pz_0d!75XT0)LA-qKriy3tjyqgSw^#7nYNiE3x<0<7x+WH?3`vxBpOO@e;?5Az@U zu=ramjb6Co+@_roEtL~;l|E88^;Kpum{0YUPRxHhhYt@o6&B7;nB)oyC@ti0c}F$| zN!zK6Vih;DgTVs&20hVwVBIiVn6E*@UCs=yg3kS}F=77;i*VUw0al@Yf6}U8gx#79)+9*`Ls zZH=&gHBN9&MhppIddeac0MNTB{oN8}lL@-_u4ZW4%$+>O^;sxoSxi zvFACybJSM*Df8t5{gW>BA?6`7gY^tv`#Ei-HdX7ds__0c%4FlEQOsIzowZ`w8MElk z+FCoH?h|q91WuN5AhJKpT~=Q5dvmSsbdG(Yzcj~L$MG{g_OD`%*3Z#Vo8}nnjCAF5 ze$ZZG0|tqA_6jijD_HmkkCnQ7X~qz@j(IrB)5RC8zn(9Ei`Go49qn zk}h^>&4_Xm!~o$Sb}vQOrF|$B)I*znE!mr%@ED80d7USmq7Kzz_wm&m(!ZoK{%uIn zVF)?Dc`(BEa!yr5y(WRE?_UtXbnx1$)<)}ZYpJwlB~ZZ~WKa)NRd7`7p`U$0QJ47T z8|tcJ@!1cvp1M+N)`0l7J5kMGV)oUjH9WWC$P#zuYKfA#XN4N=|eK?-L0@#B;feTM557P*b>4MXwJY5~4|9fi zL}@rl`=|`g01xd4*rUy1v37tlmV^GoGl*Aafwg`m_gX`#l&HhXx@n>K2O4pVYNDTs zAh&`(jUh_NPd#2nPW%i+e@m$;JBa#qe=!LDWdgNef6Hc|UftwoG^28g-Qst3gjUe8 zPWzu0sf|+yV-vU8=jjkz&uY%s1}luGKO>(|KmCa8<|an%XZ_}gBlfhYQG9x>A_TF$W$HP7zLu6hXy!Ql*&T?d*XM*>JI?hFr zS3JiIt)!kW#L+EH{mLMsnSks>wy6gZcv;p(dDTxJfriBUFU2{rhMJv0%t{z}iyDho%1#+$6IQT{DahD)WSUFd8&P1f}FR8&%6^qvH%gMO10K5sNP$+EvzejtV|0)E_|D!h_Z3Ku3PKbj{xLT2;~ ztjei8Weo3d7(V9zcl0XyUuHI>4yd6l9qJkL6z@_2Wvt8|u8Gz~U83NdU;_C;r&oi6 zzCg{QIo09Ks7%(`HAC3BS%`6R;MYa-)1kcmh1}&5YjGJ-?jAbUjRcv$1B*VKk*^`P zeg@v!kTFsf#rr-CqMsRE@pYi4UjDuW#OpmCP-yMUr6#rx&yYk;U;*#WrV8*jS11RY z;5%mN8t*Vv&3XjX`vK_p396`V5bxT|)JbYo=kv9bJLly8E6IM804Es94xb4s{RO4b zDy)M^e0BwRUU5dZgO#(B_;NQf{jcBvUl>wn&-*L z94%tz)-Y4~&|Oo(=xgydo!n_6<2VLd|0`?uIrB7%89Tx1c@J*m=UxSvw=AraJIv4r zR?;DGjC<6lR)U{kfkicCPWF?nNr9=ql>e*Lz#3#ZH0~SZld;_83rNdn-t8H%{oTxS z0<+P8@hrs(KgS||kKHRrrMa8=-@=`a^E8*4ttn)Lz$+Nx6|ymBSvw}zEy50qWn3eu zFlfr24b_&%vywvDq7s}PU8v^U4aUq!$Wmg?ZD9z~4`iZTU`-zm>3X!{>RlbfHuWer|quHUl;_Aqy$s`*vS{CVDT zF|4?QPyZiL?*SiG^}PS@y?0ACm5xa7AW9dhQba+TAHV{31OX92P(VclLF@$)5wIYr zNK>RKqI8fVQlv_gD!nBn*}e7mevZNZ--1&smvv}`o~ufIwYn^2aYl8XHCG?YfNSsJa~{t!h&9b-9VT*5pMFZWFw1tx z$Ypl6wLEh<@7@O8o1!&S8PUJIbC{SEh@b4%Lf1LT+>Vh2-vl|R249y!N1TF+9_L!B zf2hW{YM@VYevx1&iZSzY@SLRMA2?k&?4LTHqkfYgC^+VN07bU{OuO% zUWClk8QqeBR9)mVN06m0WSUiDUCvS|jXtK@dp|Qapidf&|ok^T>xz4U3_x(~z$SBR;^`EAaCu_fTiK z2v=WYPRavSJ~bE*uUC+9~mz|n_@VfN=F>Q%UT z2kX%oj;c)M?je46;mWtLnr30eOhwAoi|hhpDZy2Zk%?Ahk#|SdOvWE!{#|+97V5R& zueIQ%gPdPfgre8s&;JZ$j5b7HiJ)U=E6v-kE?y? zE6F+v)m5L90aflmUW6>Mw|xkc0?PbvkJM)MBSG! z!E+>bGqN+x&}J3la8n~@U5Y1{W+Xo2J;`h`;Gml9uVtX#b+~UQ5-xpx4$XL$(Wn>Q z1y=JS8m%^8b&$bI%o7}DxUn&xY{O?Wxko$h5GjyMA)8D^7FOUp&F4PXnU^qR)N|`3 zy8AHnx*fU7W;VdrBUu%hbA4ue9m-XLrsY|)uJA<}Mw`OyU1m{{dBzH;s55T$wUmCa zS))dL<{;d+gY~??$PY356h66w=dI`cvq*TH>(4XuTKuIlBMqY~eeNqfC|W7evWugq6InnkEqs-a4QSIR-#9JIkIw8mf1 zpN_&%SoKudXc1Xm;>nt^JsOLlDJ{MO_~RhYy~5bFGZo=e zC7^pI&vl`e!8p?x#jV^?h*l?|yIOIIMWO9W%MTR-Y zKa1vY_*5o$5*CH-t})btBB}7vQLZ=#C#A#r<@ub&o%cakNqK4BD_OAWyP$)#X%xzI zXFT~_vkY5lCo6a>@3mx=cA}GJK^>dS!QSW|^((uCwEYYHGT7&bW1DhL#d~`TR`CwF ztQq%8MK1Rv^&449kMFD8;}DPhUHlA zY-W**^wfg?szHw&em`A64SgnyCyOhOL61Kf!2$l7$q3cKGYYNJ&?Pwq=hk7?p(1>z zUW|V;5~{b5&UD@_0zHbcZtAP)v8q|z@e1qY!wVOXqQcrcQ8J6M>SR->GA>+J6v~$6 z^FGuGn9X%4qAy{CAN{r`JFQ8O)##R;TXndIk6piqAp`gVXgAIMurBhE6 z_L@3-p6Bjh*C3;p;rc6lUE}Ktzn|c#5$;4 zVT{+{QWlIT#PhT+aU>y|dncInS=M?VGstI7hmf!htpC-5uUzIPggiwdwE894(Ha$e zS7f~#z=P6}Y1~bmVHS)>y-u?k^GVkHAI2-*(l|Bxv(Qz0xM-{E^xk!(^*a0`S(iOi zoS&jhA#X(aJqvoOR7g*_NA=l~Y$N700S^JlF zz}+hNYl2mjmXelCGP@M$BWh^1fboQSl2hF^6TT6`ox0wNZUL0GxS~YCj7>%yVcsFG za*@YWD3Q+HM2A%FW^sMMN}2pUgw?3}P|g1u6gba}FY>>7)?VhP>Ps*3N|Go|Ebb5` zgpXIc;B{)j=t}XwG|J5dBP_;K^wbz5$%BI0!J-9MYt5wxFF|Ydl@*TPVQ3)Q==rjA z@_Ch8z`Z`)BJExZ8du`pHy2P?|BDWwEdAdcud}YXj8mP9wY#gkZGOQjUgnNx`I{tB zYpY(jPQlL@BQY73_(zhY`ILr&MR_GjEW($lCZxkMJh39QEtG^Xbc^uhLVMvx!ECY_ z|3#j2ji+e@T0!lE>XfQ(zmj6v-=c;3>Sl6Z%^{6Z5E6t+2BRtL&wKg*KB+Fo>a!|D zsC4Ek?nq&kH9m4TxR1tKc$XCJtyxII3ilY*9-Huo$5<~il6=1NpwDH#^==^+qNot& z`I!ZDkj4oYtXwAVxzI)2n8}k0cMpsE8;ql{cd~(2P(NkiB8Jd>!T(8<@E0%et?`sgG;FL+LfI~MY= zC>Q14;%AS~st#JuRZX!GT%T{n1 zZ32p3W(|d7DQioze2SI61m~XO9m&Tf#-#DYp{KMSwG(KCD%`td!G2VM|0|&J%kiwD ze2JH&Wz^3(kDsTJ16c=G;U8Is>biV^pX%$ax^H=h8bdC>>np(ij4q6_`47%t)-czl7ZUN;Lu~4t)Oy&}x z|KkNbCW%i)0)kG*(|{t@<^npxK<|iPE0x9DN-=kjxcIFY%R50dp8{h&zg_#c9%ldV;)3t%X*`WbH&}3kq2L#l+GPimCWTYmmwsmMR#T zcJmTkBfC-BOFZK;^Ha?A8nZry23D8oQ;boTkx)LR4L!yszD_cGp@M1z(qO5~xE$0i z4QST?EFQodH0D{?%oIMOXQ-FAo-Ur#y`|gS0xpqt8Sw7ag7rw_4qC-3JS~f>U8JBm zTxhaK*CJ-qjcDj6%e z?Z#ROhz(?7Q;6^C@;L(jWT&A5N#?>d`3RzgPdSpR~Pb6>hz{O$G&(iVI1PQK_ zTxq4nli6G$8E~LMj2TvDB3M_i%RRG0cQ z1(cN~lFg_@2l216V2d(mSw@HQ?H9o8j}-*i8% z&rPg@be?R#vQVlNpD)FDGx(c$PL=^B2nBbMmvw=!B5@S4sPu+xrGUSjVI0T#WRkJSCXpAbeO9(;MR=qL^C}!k1vs@dW79Zf{YY|e@U-i2 z#&Pbi{Z+rqhLeYPf_tAW_|i@#O)ZI$)|2KI_XvF>&b{Qd$SSJ|=jqrd5+omd+ERP*_%)_(8j_{OJ;`MoDO+QE4BFae4zZnIqBHv61Bt;5n7h?q!#TB24w=_G^MEoi3DZ5WtCqe1*wA8gUp-kcL)dK-yfpiYzz9p2Y>?yUc=7QmD>P zS((}mOBKAQ-A$jB&e6(TX71t$%~(>Hhdd~2pM>9nnaBp$o_Zb1DfX*plEhrF=F&=q zJR9Xnh18Lbk)L`4`8v%rWJhT(l3Cd{@*K6QMWLE({6Zf%vp|Zp=6O6T2RXUGXH?^$ zUG^xFdx3FXMp_H49qn$CY@4eR{4YJG9V3l3slwh+i7(whlW*w|t%^n_$tuc~8jE5{ zx=*3MChNX%rRB{@M@S!Ch69BDt-ngkYwV(dBu|`trGQeRrtD^EYtc;>uZiccdt@_< zT>h%}wJU2aGtpXAkK< z4ALRuTk(=~R|cyi{VA!GO=R&-7PHQRF5*$epcR!$V-!W<3VB^c_^D`;w2AB%ajBjz zDVA*_c@y8t5)+lgJ+hZXeeDj~86>6JO$u!ZA-PIUv|~vgq>&^Q@?aE^kQF0)OY$pg zNzagW68@9$E@k6LYiUQYd5XL`%|&`5ox7Dm{-pn!^qPb=V&oB3Te z8PXS8EzSJ@qrPNWmYpan$tc{rd(dacD->6=;qQtYf%7>jln*)WRTNaCr~ zWH%C8m+S^bJkDc194XMTvaQ5j2KS}h20lt*w8i0&LJlsB4iv_2V$e*Uxb%^tYLZ=X zkmjf_{nI*#&$Kp*5@?)--5R7#4`PRfoIYU>ui_OvN^&AvAC8G1`gG zGd@KX6m_++=X6%4$dS&ew3B7>tcrZg1FFE2wObVOrlPE}1f>6@Idw02&u93l=#{jf zbdY38(sa4N8o$WzqP8qq`6_XK7DhirXIZ1N9`s5Umh1q<5VcbjWwyn5Uw)WYMZ35B z=t6H>a&sO|Jzg*)#X0^d*uiCIi({`q4{0)a)6z@Qq4H)$>}uDS{U=>llqX5P zGq{^PCF%M9pLeBY#S`*b#A_O*G_dTJk_Bt8NQS;D6|9c@AVqbh$wd=Mq~}Xm=|x+G_f({m1-?W+fxd-w>)#{_7xQnb5~%#4Z{n+Ta{R*E z=YK`k)0afXzarm0>5u0;u&FU5XyWBlHP^&E0&ZA5G>eSoAINIlO}>0H{No+u)t95g z-2$)<1~T`PoPvXVLB>!&>V-Q~Eixt;1=iiS)O;KuOM^4ju{Mme}G`&G;g2dMfEW6t{_4(6pMqbD7;LvR`)`i*|%Z%Bf&E&2O zCu_$Ge)YF;>Rg<@u+3Pr1X-28P%mUtuQfHGUlHe}@AKJ}tn_sMZvOx^zHe}SgkFHf zLpMO)J7GLQw#n(hVP#(ch5K2~>>i;i?+0pN8dEiN!|!2C$R9J^J>}93L zl6O%TPB%dAUd5^Dmz-;FfF|oW2YU}%9HR27acCUb>Z{1z*+GWNLqrTpkn^^Rth}c1 z{WPkO&LHc9$Tz*4_fx6wNd=W~J}2N0a%T1@87{Yn9wcAoFSzU>&d?@s^&_FtUMNIHN4iJSoK-H#tA$-N^?}6*)!hQx$BafKp%wL!-l1=ae&;r*D+1tKifRa4D)=aOgCE@hhjU)9D9Vb z(FSD4d`?cyRZyopayniPjyeEp;791E>SR9B@swOXb(x$DTHir($m8G++(mxlz2sw! z;B;mvePQzpDnx&yp6OfGx4hwyFK{P08lNI3lgW4O3VPtztj(QioGyPtKie_Emwpzfi4RaoFA`tR>_cEDKtb7nvJ8W*i3Xs|Dk@OsBk8$)K7B5^4!!6dB=v!Fhj@y;2Xk*hF^U zCuD7bkC2X`zqJ z?&0<+kH%V)E8ETbHS~zL!Fko*Yro?>?B=+u!PL3v|4Ln0J5_qnM|6~HB--8BeeG)Y z+MK&?OwUjC+8B@fpVB#e3K+-lWIbK9ez93ukHt=g?=dz6W1Twor}=r#RKLGhBIs;c z(Xx?8!m}c^!=8~EnvkrYsCI43=q=Xy#w@j_0(^tC80? zIXOAXuVrkG7Ec)vdo1Ox=%>abXql1T%U&0|r+uIIKf?{x0b8P~^{%lxbkaKrQsaGj z$?SPoU&tw*`$^89iRu1k^DnPT>iy|2W|>*XQ=H6~iau3jlX=40WjDN6dm>YRN?L_o}(EV2Z z@K0#*!HFZzZf~3OL$bPSg$EcDzzmIr6Vz#LPd=32JiB{#_3MptTO_iQ_vS84w#}#! zpOd*N_H2=xbcpsee=9sC(=9ZrP#Fa3a`5n zjdXJ_=Z?s~!*Aio!6tq^xIgl{IXM`LiB-?apaQ9O@Uzj^iP?u8AN-U~PLrT2I7&n4 zFgL=TYTteR)7*CxmlFGOD&sijAof-BacyMaMfP` z=2fp7>B&cuA3I}{>zz5_jp4tI>EU04sn+FCwsXLE%6mSv({1Ig@#lGcLmoIu2j~n% zu8;9G`At31GXDjY{JV@->D+diddf3s>9Jl`Vsq|8x&6TnU!T7|nd2JD#u)#wHy}Tr ze90~iTH@@)Gwi87+?VO8e$xC1blHBOtvze?4i%*`aSupDgM0&QEdyk&a>2cBW9o`V zl4rTlchJ|xj0cRg;4kxV@Oq+Z!b-mG{+bw^zcqQq-kAIs4AqqI0qdo3kos}@@ytQ- z>6yjSd&U=}{256aZ-i#J5%+Pse6mfVQSJ!)7khScmfetghs#(QwIcN*k(d)H8(A7T zZvM|4jkX`^KjZX7V&Ab_+F8zB?o78fdFcb$AzGPz*q{4^#!z)w%YWbf*skt0amv}X z9LN9Az27_(dN{ly);hi`-YNA^`l8g^QwOH5iG67G3+Iw`JjZ$7shsGT-zu>@e@@=J z`IDWWoSFW_(1h^B$k|w}l<~3ADKAH+gtIMbeEcWf_4c9U*~H6<*AsUq-?4M-QtoB% zTkOm!WUUWnml{ldecYjmnB6D8YX0kqx{2M+a}Ir~jOO9vk?hFQ*fY`L(c_U_Wi5DSj^MEjecgr+Hb86{}TC; z3XZ1H@1u=yKIVs;TXW2_1|25+?d};jk{n^jondxSXM@{?c{DVyn~ji_n&IEV!@{py zvy5U!X6QYyx;N16N^OW||8Cc^AGKFd`PkLXcAI$(u>W=wka!z>ub$K?-w0XeHnXvH zcX(TPaHLn{u4u97x=3E6TjcHVD^xtaXq*nlfqS(jneWVUyyUIUR`(UESDPBGjWOmc z)=ktkGz!nKo}|L(aHu2}&M5CiH^+V#MAb#f#ddq=8M}yG(Y@Dg?oM~ zH8A&D{i!JZ%p7WNHC&LPNBCL(Z_YC3X=jd|pDYQg>p#xl&IP-ocLdzEDc)$X+#aHP zW;Np#MtX+cbQi+aB5y+NnUPcB*CM^bKU(dvY#SL{sJ>p~PoxfOAbIb7{9nOpnMYQ1 z8!)W4gMoV)s$C#Y|1*E1*VDTWe&`Hmw-a|qxL57N_Fdi`)Hbzozw{pTOn(@b#$yJ3 zBg`e?tKn&p=Fuv#JEAS4i=xj*%tgZZqzw^MgO%|j81eA06{gn zHrg_FUu;HnXS8(mfyk}!(N63O>MG&*6!361dN+fV^EEsBaOxF0fiiJ{N`on6f42!j zRNXhCi{BvUh;xuG7ESGA$(hbDr<9Wd=5E~kh#dZ{Af#U~mRLq)V&ro4_LM(jb>i2e zug11V2S&D2DY3~cPZncZkVCavw%4BSfrI=vsDda?g?uF>pfr{4KZDs*(tqDO>>h$c z4!PTz*W>iH*iX;n%5F=yI~6rg5lPq)>dTrn4c`_?i?)jHix!K`iH?j;id+ucRvW5` z27yex1`p#jEA}~fW2>mFD~aZC{XPCaV3<_!Kk!OW_xh?^*RAN9?ggZwru!5KNB7dd z;hZ<#H_7{KLsfa0I=$7#+eUwLq4}lxtvT0>QL!`tUVG5$W8G&pvr??nbRaK9W%OR- zNwA{_U?r|cul(#!L2v&6?pQA>ahlWrxj9eV=iK3jd3T{_(5s@OKNj0Pi~d&wvE;ka z7v_3sVJHcTauOWG2k7(rxbccn-RxlgL@nWU;|cQ*^KFi!cViZ17Y5MC`;8V5A=b#ij&a$uO+ya-3;C9_&HlGdU$KPA{O5cu+3> zT%*uDqa7%1%Z#l-Tk|Yc%g3q8ex0oJo^()K3FhJ=FiY;Bzx%!*2dtLvcpPA*gCy7; z-=Pg1%mQdu8e6^_K65FsM&<@j;Q1?KHZx=xPvQ3+04J#@e%bd}?)AXiIqL5~@14iS zu8MX0JKe+*{%UG%7U9{B@(<&C9HjDkiP24JY9~_8}(Wmq<3wC<7joLvgqYeDvf@Ro^+W*s3pe>~9ReSuL1&n?T zmi}$*tc$UXx8Q&OLB??!UilO(dmGBP#;e$eACQM{@*Fveiy6lezP}-VQm1bd$+dn0 zU#KO1*mbQj zL%oTR2u-mE`NQ(2T{20BkqtkUxYbkCi#>*qH6I*~L5w!TXoJ+<9*WV2a}ksp&u8Cd zm0E`C@SIlo=JSx6gLszxLJ8j@ue2Nytj_TB?|5_{vf}rEEcXl<1Ml*V@*=m<;S!_? z;v8FuzLdl-C;Dg1rv~O4KHsygqi;#~xj~GD)8Ne;c zSpAT7aHvE7f&NLun3+$-(YsLj6zBre;h1Hhb_|0vSHRteSQ|wP@5akkoa$C^JEjoT znu*=FoB62o+W%O~T;%pGo>7-^r4j*EoboA<`kzNO9wR33HNN(n>~LkUq^A)#nafC< za$5KxYd46iyRbtLV*QF43+5^o%?PtwD zg&&L3|8D^6`?B#fJz>6r4mVhrbMVX)bpCmPzii@u>*%_bjck-aI(i|e>X$Hr`DT(Q ztX^lEvA9kU|LM!~vWfl}p>OCJTN!U*G1NK=M^&Y+W*yu(jwn=lVk&RYH{li#NLsL- z+Y=SZ zCAxPGe5xWuQ-*+?H;=jYr}sbx@t0I$30sIttqj)Cq4g^`aVYus_rhPfT(co4ZLDC8 zU*pLUqX+TW`p{q~^@79M2acdASHdwhj9ScnFL!?y6rgjgdJm&2qgTb{KzMT)QDI^A zKZ@PD1YK~R+NbBR+2*mP>ac0?{O5`J*~Dfm5ix5Bhh1WpVIvf3Ya9Vp=MX);XT!1M zpj8ueQe8Nv29%i++Ta%@yc?#!z)xSAkUtpjA0K7<52GdU8Ul|wuFX z+ET6c9a8cizFi|a;f`Y`yoQI;4RoBk)IO~XzQsy7WPFaq)T0+eu}~}M*OO@7+st|+ z+~1Jht`Su1&#sw6bx3*kiGhr7BiDhS6RKe>=N%}D)j9=^xsG1!$~e2ApX*Tf*@Bvp z)9fE>;pZG|rZYr+JJNUVbH==#=lo0Ea6bFMCOA5S8pQdb)1d$MFupM+;J27qN~Mf} z)N1r$#&5A}G$GPLMUY`mqyJ$MV;H9gZHRpSiuUS&6m=sO`5#u$T%^1#{>M3j=Z*2Q z&#~Hdupi!`a=(gq#U0>9y~fUZyMdi&-|W2V+~#~p=ju2W={=Cw68JjZ!~LRTV|T^B zO*tCd5dAn(B(lQnX=Dqj(%qe`lpJV3;I+l7+Z0Ng>!KB7-$$;1K)DHAoL#}!)b*F~ zR)SFxu@BmN?9TR|$*{B7P4z2b-*)mRxl#8R*6VP$iL=>RdWD_e&juFZ+yD#rTh1Xf%gwb|Txh+;h%jbe$?o=aEI>Z>$p0aQydp&*(||?>s=X z|5Nu-yCWSRKCz!k>_|l2P55CI+*`eyy_&?Z=XlfHpY1))KSXR^1Rd{Z@(C zyKy7!&h&ceEz--REvC=acUCcDc2L>vlYA|anW&RrF>hnCsxvv*LI0|Ku_5u!X$|9D zW97p`jQzn_?^d^q{afiBZWu&T_Y=mq&lSvF@{8j(gp`&uN$JK=dN!mI7yC zWT<=i?%4aO&&8*ttxBtu(K_whlwV?X!U^L4_kb(EJeigJF>xsW-NYOx4}07VJsZi0 z{lTG7|5(ddpJ)|xm!AuMfZ^^;{+2vy*LJqpTkUmj)Spjh!mA#g3`3jz-p(8LK&P|& zyz@?CXfnfZ4=&d`#`ws<_{r2Gsa;b0q*YIEl=@wyq1BMHmLBe;x$?AUY zCH;tN*^B5i=F{cmPBg>>vogKTu10@L854gY{&C7nDZ5j$qBTH9%`&$8_1wvJPkNN) z<$K8^$wlt>egwb%h?R`K5W73}Vz``ji}g8?v-93(?nGxPl4053C3`tN+#Kh2_hG8_ z4dyU!U{;#QM@1;L9MQj>mqrL1aFS|NV{^;hwwjRJU-|Il7oPBHB$AJ=Vlj zbY(@N^A27{3HId=`0Ocqz}$lOybizUhEWf%e}{1a^z21OXCu=%4en}JESQ<>ZtqZK zUkkl?8(Q+3FP!umRIcay4%o1_@l`db2m;$+dW$}Z=k+C8_6IBiokc4vLG>ci4J?k6ifIA`kMVgefrf<8k)!eOCg26GzX~1pN@6fmYwth_QZG8n~!C$>P-ZqCw9d^ zUXQ@TQpc|MIhmS{w=;vh(%F13=ZxVGs?|>O%n&<4Rd$3zyw*74~w5qYmtKSCZI#iZ({$x8DuYzHu*yJF7L+PnE<*o`?DopJHKDR< zC6#TE&*{CMp$v(DwK~Wwi(_Y6_&3|2Qv-aMW;{)2-^vkC<#J(VKxM4NF5Gbsycb~= z)3Nh)68SK^14=6h!$pt@RRFKW=RD1Q_fW}ug1g(;)=y#^w#5b?&bnk_=|74e{3uni zTe)^Lp3Pc(nJ2KMRX6t>I1FQvgvy+?T*X599Zt-^;#U6bML2IOD|CVD^BM8y@c1rX zXEK|sNc1y&$B~l9S*@@6+iASb^4R)MB7e)VARh>R@G5yz{awcG;f~>1Ms*~43cWQ~ zg2q~cSnLwyX9?Cq-{4mx+nkTp`#lKt_05@_=PvfP`1dfXQb8TCA!gvy%?CMS2G&w_ zy6t_)+2!BCC9pt-fRk05zgXaB972Qb!rwpUU!$|wd{$+BFd971dH8`>&>M4z@Ye{n z^QRHP_|a%?)bTs8w_GIBHGwIqoQGe%5V^g{*hh{-5$fj;`P+ydmH<1r29oqe&>SrEKSGhfqc24t*7R%c z{h~h(i}VKCXA1JR4J5~7`1_qfy69@W9eTl7&FS_Qux80-+IbmMK#TElcxd>cRI zS6@BGU%>x+fwKs7QK-4`3A*kb{|*q3ZejkNf;6KaSRmy>i~Tm#1dN9#JMg5Ri1Td2 zUvd2fc({{6TqWxOl-sUE5tcD}n>f^4hU>?TasH!t;}witPUkK$lE;Y!l*TXoF7&d$ z72PuiY9Hln|6gNr@VJq~dC`MNnQ3(LpW_Kt438SoX~?06FZvPj+r{{zt0mc-tXG3O zKV+Y}6S}I3zZrTd&!20so<=*an@5ykI+FGts0S0^s=34!dKx?ZBcR6)Gcx^UMrC}h z`ba+K^FbX}c)#(lHyM<-R3pou!}%1R4xIlId>1F%VRLAXf8Kb-{|J2H<9L7BL?+gR zMskjKg-=vLj-LXv=RU&(U$ZY9^)r18?&iK9LKXZ3Bz8I{*WBrWS+w<%arI3l=iNgI5`im2x5k%Be@t&`-1GGfXZo<}%hkir*Z1Go- zGm^yjx&$hq@P(3iBVUCU`aj~Ee@is0DcsQzUDSxPh79)STD7u;{Wy6p!4gZb#u@G8F&=$5D|SH)VNB< zTf|-hxZo_2-L?J}KZI`v-l<H5#ZRhaUK|FH<7&lY!uF8W$SCmdQm65<4^l^Rs zrNvkosYIq$vY)kpHW^TAIM}O|K;o$s6vIAghn3I{kEw!D17w>x9cqMO^c+{tB0FIN z-AC8?HPMFCp$>5c<3nQ<9S6r78OF1mjyw#y&>7HSyMUCFO0;SfF^3-bXSW%{!4 zT-M{P-*POH+So=<`^!BGjQ%P9Qa{4(6f#W%a&d#Bvf zoSNJZ{`1ph2{kf3^F3nVxgcJZH2UL%&i5zdXHCVTJ`SRggJyzHR zbsE6_YR7Lih`7#V4PIqMM-b~-$_`(GciW)vW)klm%zoL7y*SDK`w4N}S!iXUGbPY) z%KK|V21{G)2W1}S@C^FtapiB&Ox5Nl9Mg!%QfDl_9&mdTb_3;RUL;Dpm#-82yabmj z_fu6Y<%oG#!lIJ3CNz+>SbbZOo9hkuc?2E%hbGN|LkAV&JJl3=<)pyvf6h}+N8r{OV_OI+MxxAhnyb+pD zPnoVnFdLA?)d6I{7s2{^5V`8;pJ!LQA8i#y&$J;+tUIzdfSBNV;v-*^nUfE_AA?6N z<01Cyuh9($8OM64BHOnO`)UVfRgZ}DIyA!>#jY7aIx{K`KhC1L zKzIGZ?4Ll2KPG!gIRU$|_}3G;X@oXhO%6~#tNjfzuJ*=PVAHjL5@(5z)PP5NvzuOr z!oMK@uVMqc*f;G%SIOPEjJ8WbuTEfhJx`3L7dz|+7!Pq8+8q+~yeqb8y(M3LSr^UqCdXdTVDV%&5oxOw8&kq>;5cJ1NB8=16@y5U( zvzf&aI!W$8<4hqwI*NJ!gJx>L|HI(CVVr`sAqv|DebXO%`gb^O9k$lftZ@d}UVlQj zH;Lwhc+cn_;+^k^Ro6%ItH8fMvRC&2&v7xxa2JuQ$63n~?2m5}3F=ASS3ABgfRnL| zSkO<%+DN`fU{Q^MAHTq^t-y(sqSsoB)!1VT>9TMuTIw>f=J%mpBcgTR6Cpo=uVt~D zb|RYeBm2Y(EY)hr-V9c(C49G-)ozJq+y#nDFFY0X4GOWhj^kNZ(S>(2`bt=B{jo3Q zjcg@?)(td{?(E8gk%~?17n`u37c$3Kfu665kJ*O(4J0x$$>zZmld%ixa-Y}m;l9CM zrH>f4M!s+R8EAwCtU-2gf@mN(c$`UXfUdjX|2)45w%}<0Ja+0)5cby?KDPGzXpMW2 zyFY>uQgjxrT@)O#OUU;o^hj5%&+g3TV@Bqv!w7epiqv9BAy4R7EMl9;`%T>AFgcbp z*u%omSLh`F!G9OoErre0jFou>e`z0R+9S|Vqp(>m?!24R%l3G*)7hyi@!mh|&K-gs z?A;Ht1Fb-}l^|!+W_{GXcLo|_3v1Yqc~4>oeBbD9L7R_d z-q-LS_M`W^`uqKV=%jhv?dayYWxZ0~2ktWWhOdsv(~#45L;XQ{D~H~!DSUC`IU*9% zt;ZtOqGvdP-WO>TSrE=KHyC4#M+`FaSg-Qr_jM%Z*CmLsYdj7Qy?|xa4UEql{!L_+ z?etzISL6$F-P+nA+f9B6uJu(gAgg4a(a`Rl|9P@Y;u(6kp9bmvVrW~qM0A_=d$cTB9A&JFoZ|oO zxAVHYo9!=>lkC*wndH+>(l*`3oN#+&CuI6_-Nyc2_ak=|r_^cwLhmcDty`UJhdg7V zwIlLQO4WGh)VtE2N}rsTnfgtYQD-^% zZ1*`k$(U#s)bd7nxkN&qw3?esqkp8l7poWFp1L^gXuNdl;MB{pdXY=vqNWk_b6X@2 zC5Godp1&(^M_#35S347qooAdg$AxEy!x1+!ijGzN%#+4hvX{Q|?&7TfZl^A}KsCso zc*rg1EhT%R83>)toO#X;|6;N?__2%JbZ0-_>(_q5I%)Jx`91nd{Nwn)>3!1wix17n zPTilBVP7N-b490`P1@>FGh$ht{kO>}=$?2ZuW|n1{84%DCdSyk-F@D!&;etW zSt>HzdOT7qa*TeqK7I2x`Rj;)J>z76e!Iw-Yag(ClOb8bzSG`pXE+@|uQkX?SmeH8 zZ)Zn388i(qv9eQU$39CPlzKRQQpT^T4Ku2xeH^!96{3#WFVw`F;=G%9CoeB=b?)H2 zcKKV9o9!38)pQORN$0dDBFDn_MXX4p@RR0XCj&J44~$>@1;$_I7vb*lF41|ZhvIK#tWR5!+9zW~>PaHzpGF=b zlK8rR*lw5XlSt3E^P1=1kxV2`I@#WJe2=-t6XEx)cf%FJmBWu(IrITvfXwZ8UHX{i zI9=>#lN0S($wSE(?T6^4R?J>$cLgWD99Y{`z-Ip0ZxQ~8k=KcbW4+Q&r)H#|i;sx6 zN?#G36#F9lu+_#m>K$^=lGXHEazLV9a)9$IeXutAAK;xV4{bLGgW9^!{EyCei?On6 z`nBBp?gQjs4R^=E@#Wkfy@}qd-iKJt{pd?JjU93o@s2M!kN(q`iRE0}{1goQS=Lk5 z?(m3kyYL_3+TkC=y{-RQrOd|WDDWZcU}0F~dpsJP@n+L?Vlo)c3%TF#{;c4vR|#)B zMkd2dzYE2J8}D(MBuSt7c={4J8*@I4E1u$-)%8oqg>!PK>J> zG2?$Ah)w|&bDi-!xl*5jz&gu#6kE8gv7bF@7dul4Y{EReu@iU^-(#67zH$#1*4_B8 zt@s&b9AHof+v%9?@v{ou8ycYh{)Y`Vn7jmbU98!^*zNvhm#Rm!QPHJ=?EPcWw%_qJ zmCWabSSic-eT%&B}^ zJg6=_t1ULr!+f{LR=As;zZ>?qx?kPHp5Kx^rXimw!=9*^V+gC^KP>UJSoXv4!Fppk zlw#k>BGzEhvtlQ?G0$O1{g2V~;*@Cwmism$j*5&v%RL)IZ4+PHp!`m9 z8H7i03<{iM)~d}F){bUh4ePQpuT;CNx@{pk={Lo56^D~$(-_Lv#S#-HM@@VTRmO;R zS=e?F>=ae9tCsyhL8SE%Ps?XCr$m@`x96tHyiyz zM^?KiHyO#E#h*RLZ^Qx$s7z;1W~8}~DOmt_UBy}``3k~OfM@ioQ1e^r@C z#+guE<27T9yU8CFM7?d;%|-k%oFKkvbPjJbzNEj&H&{gDu!0?TvTp{ry5Eo`^c?** z@9`&@`+^O|1bQF!HqZEtjVGW@ZJtn@ctRD{Ghx{7dLs=4_%X&-a+f(pfG$DM#~kl{ zWexE^2wpUP@aJ<9`!+pHFZkc%pGTovN8>orsJo2AZkzB5XQ6q@y8=h-!&197G}gH2 z&asNPuUq}S9OE3){)U<7{ACUZuJ~`W{>OreW-I@O`H7ng?bo}1gsV9%!$bUvUd2e< zu3)_wtZ)ZJKcXvFIqwVO4Wp0uJsmC=yUol8tO3qyt3%Mr?`O=#_PW`dZ7ua{7%PZD zzUFTZ^*3T(7y1$P4HfYpHC-}4AB$9XKv6Q^^ggyGxRb5LWNqAOjPY8TpqmEtu=IAB z|Agv0N#kkGy=VBtsWONLl}zk9=X|&YHqoJW}XP`_q%&_ ztU7ciJBX(^*B@X6=nyaig9puL{J*WZd!9%l2#j>xtVu`DnO^nCHTzrh&Cq3Um^sa9 z624?VX@2W}<`1>%5L5O29HM=zeamP<{(xoJ!90-Qml!_2Aqm3f!(9-RIP=kbf^BKofTlQ+zI-|tHwrQN}1^8f17CFi&qHtOJ^ zy~j!JS=Mx&Ux6I(HF*0El6^56H2>O$s&w1Yt=Q*G`Z{ubI}xF7RK47alue@Z!$_p= z_R#(Kj?bZic7>kxpTX|+iOSKB59uC^W#2cL31uHLDv*gW2+Dm#e6TY9ayjC>$EXLG zM&L z{W(2&3z=Slw%m{J{S28mVIsZD@V!9sF=nyTw8m!^-dz@U`VaUmE2s(jjJ%ht{t^6! zkFkb7AqGbOS)wvK@H`sQ5p*YUrI+yDyWtgkp*WQ$2k0mDpwW_;Z6!3t5`3~L+-(T2 zUm*rjjs1BJUhZN%llze6Zs?Ak)EbQ@Pw^-_o5{)6zeGsxL`R=M%RI@e0qkJC_}PaD zMrk57!$Y?kA5pEa5!?53<1pU%MB?5JjQYmgcuY^?*^I#F{)|(LSIDt_k=^0%(2qtH zVon#>AEyUKFvQ#8u4TteCCc`=|2nx>>+vpX^5jMMh-v;fccA;8SD9`ruM&^jO#jt0 z*7$G^9juRrXN5DYZ3f7!bekNeN7mWU1eXkQ} z-DUg+;GNHLYdE(gujf5>iVBrO|OI zdt>)TFPOgH+r8iQ?MwN0vPb#(_A8FYvm73pD}ruT+v40mozu1oZD zqP}8L&zlcK&W0PB9u~n4|D;>R$xg0uLjK!S&y}Lyu5P$#cp`D~*NODc40<~$xwqyF zOziMmn6<6b;qj?$i_|JQFTGmqGxHBlnErJh%I}!>Y%(2>xq{V-YK46XC9)6AfONY#3 z)(b{Ezk~ZQxe8hCf6g4Y1SfGHIp0&QvcgLX_3&Gg57Q{PJGw63Gi5=fWlEQf5}9u7 z#n8X*R&R9B**^iG&wYNiaKmWda7Q{QtquQfH4645XC!VUA8;N`?nwCdu~7N&FX7ff zS-YOU$*LR64NfM9J7>)ikvYLNKn+GyopiaCqA@K_y;-Z8*a1?cZy$6J(@B<(u@97EsPHS z5b8A=*xxvr-dKNa=vT98jnpKjXBHM!LPNzh%L^}NY6B_+KvtpzleI#Bp z$DkcMdkOo^M61M)$*B97_clA(9`ok#obYh7l7G?zliRTTC+vgHIip8-r;!!fV4St~ zT5~z8`i3}qH-D6Om-jTC&c|Z;jW^1hyNsnoY792tH;<8>-yBQPXV3h;Alsx9 z-3L~&vyG$60(}LDi!Q|ndy;D7cyP?Wm%XetxfQ#}vYyPj(irx)K}3L`Lh_~%XBXOV z3RZtfc6K4)s-n9wJKsC_Y@ZRKnv8!U#IE}IAU3BCU*c8WNwlmOk+*rAKb_|U>^Guu zYw+DV5LYe3)#`@35*mJpXEcdD^Hpd$j&H>>r?K1bX8%)_PzDx370wQAW?hV*dx+@H zX6KOqu(sf*$xJKY0kmL5AF$gBIek19%e{=IBz32|u-?~UnQz2qILImq>E|Y9ATOd~ z!K*?<(PG$OH}DeZ7>d^-bTj2?oJ1Q5U)Y`eTaIUboh3F`R7oivm z4@^i4LMk<};Qrw}LO2{J;QZhCO=nK(?tB!E%;ql_p@S*|lntXy9U-@-F(Tn%6^9PW zHWH%rF3#UtA=#zT5C3wWQ5Ubh7}1*3oDZ)g>r3NQ&A~`w;*&$Y-C6d_-XZJ9c;#5d z(3AGtZWCj)wI)=B-iII4b@p-dsi2!X+5J0+T7#`Vp-XhS$IdsNCbsvccMF*TFB?n9 z!p~yemSQig;6& zyhcWCdZB$_JmY8kGmWq{1x?z^?e3Q(8|`oq_cpkf{Zwk_o(;A2-}euMZZj8#s`=~P zBVOxJ4}8@=WEOU!TD^m*E}m04HS$9vjD?KmJlf+e&T0Bnb+Le$&_?)w0nz=*MDf98 zGRDEFty$rzSoV84Q@rT^!U@q)xL_(fSa&S!BpU5j>}y2_CUSxqCKmq(-p|9FJe{Tr zr6ze4S!he)WcI?3If3`Dv!RY;(+ib(E_YwUIovDoq%xs|Pjf44BJ9>lWL;E6OU;G@ zZ*T@*i#ms!>7Vi>)Os0>TZ&jf5#mo{$W6I}v$VF204y1y2r?t`IftPq*CY@IS$WKLp6i>pFn4Pi$6+#onR}T zqiS4cP|vi4xY(a`a=lDWOtyb7St+~l4p(xAN4feKneu}e?KWogJ8Rd6bDrUJQ0U2D zZsrWF2dlM%^P2tqR)w6EI43OEk=G;aX-kMr-BwU{BYl_6PVpG-;#|$Q7gR~A> zqwfa8Cx~Zf?mG(HFjdMoUf@sblwA8n(x%!CAgL>oflIxOFxE4+F4m|AR-L8he`ohC| z$YLMD$gYw%vI=fFPi*ZSxU4+<_8wPGAsc1^vK_FS&L)Gu4AH33JYzJmxiRFERN}tt z@Sex>m!;He+(MN`S5B%wgkydtFR2S>nM1Koe5{+z)X6O6{`WBN-OK`%=6zuuBfBqN%x>h8xS%0jr%O;6j7-8+t6nL5`O|Nxe0CFh4|_Q z^1^yC?>T7Nu1NPm?lKV`Y(>oHU97W@kkJ>Zi29G1ac@RFnlsD|>`^bH|DVG87)ESh zI&`_2^)3N-sf+S1Bx(|?WODNS05f1wSa7@WN(G}IUw+U`4aor@X?qgH4y^|=?Qo#||ld5s2pmu}1H zL|kvcr5({Z6F5J3AAMezF*k;<-#{0YMx!bdbw3<73);Sh)p|d*5?QR#Q(S3L`|*CT z)31u&7*0&)KO#Hj(3=*g-^6Np|39?PU(nm2c5xuln)9r`$tgioGLr6v+jIT#>?I57 zy4)4}{FdM_^(35Q6TRCK{Dqg%6rSkjjqflk5}9$2&(I+e_?dhoSa8*si0onvSzKTtNFaWi_V5Ykwg1sYuF7 zIBzq0xC9zo@$xD}=LcX@mtakmm8@LOHa;bUv>UvZEtSrzLacsaC<{I6KPWDAbRkO%>9`{I6uzf0pk?_9p-$NH z8in?gQd}$hRT?nN^Mq?EggN0q3a?pKo-pi%YN_)I*_&s1im(SAG9b<~e<1@4RZ1No zg!roa2w_eClv^!yb=hq~tTY)#37#cfbDcdDV(;mdFndLrG{zuwOj)WzpeqXf)MX+K zt)^}R@d8U(IPJn-mVGB=Gv#~>nNJ9bvh`#WpTuqv&YqAV_2j}n3+dRD!psudo{-Xo zRwe{Y*`OM&5bjDq8{rlT$xDc2x(ytbN(* z@&R;yqCQN*!4x8>s3v?)AI&Ff7a~In8Cg}xX}lxcRbi6pr@RSucM!s@UI`mct0|O5 zp$8OnYalD4|AXyoFZLQYWk0nJU>^>M}|v~}V639GFT1+tLWgy5;} zILgXbp1zP13)fBlkDgiBIY_95@}1=M2-8d`d-7Al%u1^)TtQ*;3;i<$orG_xjy740 zLv&CVlq~Kilux0Wif@HgE&SO+lv8oK#pi_xsWA#~PNNoI2~SOk=%TZ*_Jmm~DhOFm z*wFH<y`JXpIWIR z1zaM&(w{4QL{LKI|GCM5M{!R)mzg_ygNCLth7 z7YG|y9=ZQ(h} zOBPP-ajp{wDVtGfkfNV7QJ5zeNAIYIQB8Jbae*X6Izn9rB#}b@WFKd|4l7@Xe=jLC z*hNoa>Fh(J3jy;O>v@nnA7ZZfXzU-=7;_5u0c(IcJ zDpY57C-`eR)}t``iolOe*^`9helyXHT3nk3mDPhKlQlofTr}T{JpT+c_L<>6Jmh~^ z$wQpS{K;OU`V*nD3e~qJx~ekwtjWEETUm&DEAA4msVXRH@XS;AK!>qBnloY{16;&5 zEsqznj9u>%-h#SLU18O>V1-}ddlR4Afc5Bel6?~E#>IlK#m@P8@Ol2(hMV-Kihjt>tuZwKzN0exVf3wrzi zIFpiloNtXwR{!wp;nj4W%^`cgP4Jf2l_y>H-}3U@yZn$pGiYMWHohghaFG!u?|8BL zG0{KuBANHQgQ9*ZeA`d)yh>m(#pq?e*7z6OYj9|S@x3t_pZG=W~HeMJ52JWl^!@gF0fuO29OA#(P9!ICaV z?aUs(k^iT^5GyW&T(!3T^LU&W$nAuaJ-V1o?yiB0rCkdHe;|=AUE>Uc@I|1Gj(0 z-SUxuhskn1#o6f@@^8D5wGqYUzLRs-m1H6AVf{Yx@5B3OVeG;iD95$qLeCllm`e?; z(7xnmb}?!b9hwWjwdbzYvB=e5PSMpr@N9mx1yi* zdwB9E{J7%I_$b%#p}JvnA7dq-Bn!aA@12ehwh&#`fC$SGd<12CFTs|)3a8(TCd`2s zPr|e5yvOk{wk4JYkGAa-s7vyqAaZ!ykhBIy*Xv|JMwksXM#S9b{%K;WW1m+Uy`ReT`A5 zqhddz&)3K^ZBBl62~aim`4_xFzG^mV22=gsR4_LH6XBnbizo3uQrMX|&m`)BzNF^* zJ9D5h!#u?*b;h%6i{E;L_*EnS1G@G87aC$6r_+4#a5ZxrXqa8$wuzi9q!PiZgMB{= zN`G%u;#7N1aLl{S+v6^AdwJX3gU;_x1*eJ=vbWPKzGhI&>|$NA+FHJOYv_4Kv(~?A zo{vs;_}H=4&YQ#QmLbDaMceDZaqRm#znhf;c&`TjX4 z;WP~HGQW!ChPN8S{qfF7`x~!u@P(OUycufhSGPCiUd)}AtQFi9`#JS$T7I;j)zbYm zX(t~{e(5&yeX7s)fN1Yc{Q(B z-l^QV`3dhwGdH>_(j#2jw9UEESt;M9JrlnVEvieHN9`@f>@KFgZE_q&G{4ahb29?pFfP+mCquRKuN0<*-CEhANG^>Q9IAw z82Zl`ZmltA8fQUai#t!`&(DwNKa*JQyySmvq#2)CE6r=sKjOEfFUxp1wQI^`5GML2 z_a|<3V}1>*QFvEmzct8ojq_wj9K|yp=M{67ChyEGp0_M-jgxIY6MG}QPrPG%1Q( z9vlJ$f&_<M1YI#2Hx#MJarl-5Q zy5z05^mDMMuS2=i59UaC2c}sk&8eyu*}eeSf)s8pCm6gO92EE}xFOgO2H#j;SC9(- z^XIb8QjgZwEA0O2y5wgI>K9&ZD%kg_=G5dE<~?-RQL1%D!%R{sRGBrly~ge@!5x8q z!MV3D^rE@XrjttHc-EVC;ZF%i#nX) z=)`XfpPudH42}zY?oQJS%_dd`JCm6oCX7#X9b)SJIGf9dD(a$MlJ`I_q5J$()k@jK zbCJ?;NbCg0L74H>2z^zEU85OZjTrAu@b# zz(bByG3aMlNkCcd0Xb3?TTA@G9H9YTKX4T9-N#-JBLmgrJK2H#VBP2u`kgb@2G??y zxQCjJI*r zCW4mRs_TOc-J>&;#mqyD~!9M*HYd~|(l_%Do3~sh`RAx@(e3;@j^8WJ* z>BVxclSR!=1SS?;eO?_hOM-R9VL^EuV?FNntoQ`czXF!6AxOklPfVVynK z6}|tQ22N$NCwtU(BqXP*jJ2K}D|#`}kBp&gdLrC;X>?s8xi7GkT+WB{*jZJu-4>$7 z{h@1KclU);$2l3C1!`rscS+a4Lb#v`nn~!f)7DqM!Ty{6O8yye4>V9GKve!gW^xke zRRmG}>Beu=%oS9PLYv%5&a^-sSLqxowdpexusu#-hYRn|Z_GcOm9SbC_R{KApdLzd z#U&`8ur z+(k}a_YT~e$KCX9e`lUMCzRZTHPI?!u0W1Iqk3Vsj)h%wV?v|E2En?aSE{vj&Ae*n zv@-iL`jx+&uZ5uS%}=c2RynJgSzW=ltE!sgt?c$KbGkZ*1+)=6x)RlO4MRy@1wDqJ z#*+8>HpcRu@%XRScAIL35*7MrFmCQlXXD zBmZDESmX*eW8FN`gnXa39_dzhGrB85V^#N(!R4?}mm?bZE0s}&;MAP% z)OI6ape*1`@XqSyDy8+Mxm!h>S?p8(WfA}RkHb{C$KGk5v5J7Gr~z_mh516QByVG~ zF29)N6ww&;N}TGhPQgT2N)N(1ISU%R10)>W4x{~cTDt}=qyASYr{X6 zhU)QlZXtJ!TgtoZCVHo+Ll&ONRAv=xmL1_c09I(buZsV=Z-HILT7wKUF~6lwd;pg1 zRd#%4e3og{bPfZ5-BZ2e_r2Kf7xe?U9M6I}y7^;9;sKTa;l(zE~_c!$a17~Z0`**8^RoE(RJu^$1 zW3e*}kaeg+RR0Q=??fsZ`(xGLBENVYHk+>Sb-wTxdzIkrIpwaPR^xN`Ke#5hV0$fr zgEtNfZwsuH&8b@{;=T7y>!P3$&frCr;mLndo6Kx>D&INZzrLluQoft^bi06U+WV~U ztpl7#rBo|)_Y_c+Z-{c_CC5`9ANG`Fl;Ab|Ouu4&|Hs_t^HPG_`_t{}c5-J@nL5iW zt`F-3EW`Y|wD-Ha1dHPU&z&Dxl^((s$Uo(Vt+TpSlT{z&o9+9?m(v$#FR=&Pwe1%$ zIj%OZsA$y|PkSQT{C{LcmV=~thv&Wl`+2+mlC$9i&pnX}n6JE&-2bh+-<{*mbMIrb z2D~XCUn0TQ4@Nf5dNItDO-z0>(e16oraxd~cTw%l_V6{YwXfLg?9p~}yDnU(W$X<0 z0?P#xG#V^TRcuZ2HO&1WEcP16S~;wv>{Kot(|vS1?B__mnLT!n3WmR(HBQi(=GLQ{ zb`Y#AP!zWn-mdZcPduAT1rM1%94-?F0tB;iy zPS-Z3qkdC$Re*d>Bcd3yiOVs@8{7!SNE|$-> z!C4t_o36!6Y-ioY%W1}$_na#0%T6t7Q6A|Fs;Tv>xs+3K29@HSyqC^$?+m%N3`QLL zU=;fxLRSy3*IAAmrc;KjpgG0m8c<=M%L!QT8lR22L01B?Yt;ZR$sd%~kIQSE0G*U5cO zAOqBq{O59TA;R_N$B$30G;t5fLFb~ny|B7UT(BGS(3_m~OEk)DGR!ce8Jjr!E0IB8 z$Y~h@DKLs`TsEQw9f;4 zC=np3VjPORRwB<=jTn(+eWFzxY8T#vWVnoN`<6=JS)m7Hu)31RIt+tff4UshCzdpc zc-3+cXo~0yJs!wa_d#b%OmTJS4f8mkakn5lH-jkE4JsdBfNI;p6Q>~dkU%EO0%K8$ z2u2OnkC;+Zyz!pcc+(kMV>ls_$g8&|2mh^+H+%p$ zZ9*JsJ>Q)MSO1<^)>(G&DdKHCkRGty@T6WO*0YL;smr}1$kb{533XzJ)YrNsccG6b zH5EfZvsi{7!iE9*~!>%Dfz5z0!jt`AXs`L}3b%pL{@Oyb5{f=0t_M!S%U; zSVuQTRue0&h-wK2;Zw4drHSZ%MHas#_TvJsk&o!jKGrG#Gt3d=4%~l_bx$zZ0nm>} zbgU{Ga=G6KPTc9Xi0?jI`-FmMwyed$y> zW-$wu279UNw~4kLBrE?Dx!=w(f9&HmZIQ#Yp+_nY>>qhTOVlsqa~m0p^lR2+nfgpW zHD+mgqM(&`vX);WX$d_4JFMlu;peEON|NbV!Pzl_JnXNm(rGmJ&&220v;6)iDzc@D zDLDv$X4K1MSN&laNlC;v7wfizc(%>am^^nytRkD^;xSPS=8o zU@|Hj>tX91sZ*$$%)=N~|1HRpmMRWu+NZ~XYN?Nu48$Dk z_UQEV@I~d})19Hpht8Ru@C(Y4YmrLg=geRaY^F6j6V*-osqCMv2ZN6)q;BgAq2FLZ z?Eo{(cZ_v{`V(t3CAgr^nCY8(6nL0#@Do#bE#TIygGQT86~Jha3FTmbd!w?W>n6fe zkWamXv3n%D^oEKCFMq_CsT-Rgyq&5v5sLAwX=(Kjn5`0^SSo~C!<2K-$e~YxrnyZ1 z-Oy)1JVdJimeG91aSAL%XI%u#V;`~dv9QYC2gCF=^DWqftVSCmvV+uSUYQIXSq(H+ z8Gc_F&%)7P!xQ7jOWs4|dE2rYoX3?sGmBB!hpGjL&PVmCy`ebOVDo3<`0hY;qD$f>x z+bEz$;)A3{7CVAhs!rF5H0qx2&CX1N{V@QET?x)>7U$zscGB;hC)qgDBGDNY)Lng@ zEW#LeU=eT;8`vWoI185IO%KD%si4P&VpL=5%X@)4e#L6erb;p;n)w9sE`7^3ft#7l z?moi&&PMNd#ZJGBR=$IdD#j@m#XcLT`KP6{yh^Xz4;EX~b-^$ag#Xp+W7IF@Ms&mxggTlZ{8bEyQ z7krF`oFcoa&+7xmrx?-bJov<2h_L*O#-A+M5@Owlyjvi&8+x;Z(~qtJz4TbGqK*l* z=W{tTP#cDV0F^~K%<|^{%uH5R>u2kK))H&IRn>Z9ZZHR$5qPvmLEoI`>|Ki&aU8D0 zpQ*Qh>E@!}!aqcVEiy$Z%vmat9K;TCB_EKkg2WzrH8v|O(#a?}|_(mHZ9^O%Q`_|%Qarc~q9%*BWraqrGV zEE{n4Oa}cln{kdqlEedXLEuzE9~?vw$E6Lk6WA> zf6IJq#&aLT)jKeflEmOrumhgKLv)RdhD{v8(aEszY|z7Bl0BLLDsw&l)_!(w99D^+ z{Ig)e6VRQS)3FHJpgB7HS3Iku*xDJ%vec$xsTZssUC1RB$FoSUl91eknEm=8s}e_q(g?-rH|XS8_7pT5JNysqxf@FJu;u8#jm^J;8=aAe-}?Oyx6bBu|9z{S!ISFBollq~bYqxRhsW z&3d#B^Wwm)MYJzxIIi*q+PDs}(N;WrFRboG%>O35i(|;1;2a#DU%LC|N7q&2**mhv zqtUK&i5ZgXAv3rR`J97|KcA0LjBhfl)R9+LW);#Q_nFxF&soh&tj8)oXEDR8(K0iU zvDrNFYUFGia<-CtuO`|#4?i0=eDv!HY|OW0{L>I&78Hoh^9Wj@9HU7Ao*)*xFBi{Q zk~tbe{;?~&JP&?F9!8pnzt`t=x!L#m!qJ}yWa26apG4L+NG?Km(KFH@Gzes|L?GAh1F4dg+3q`DA=a-WU-|S{X4YtX>10m=N7z?)G)lo zAIQV$cLi(UAhuK~szgr^dE1MhvVdo)#CxlAR=wm5%89R%0sO-%a;yJhjqGKX*5E&N z!S1|*T|I(q^CDsw!a!A?XLyXw|B^X*LH=>!0mOk$>=*d*D3w_0TC8)R4pm&!r z?x-*Z={)h`UpX;fv$u8`DZoP}BD3>Bp37NziP?O_?9ISixdD#i5VcXiU}simCEoIs zO?g7;7e5K#j%pYz_-V|`NvyaT%%Je_K}wv(N9)9jf51+kPA&ZJ ztd2&u>8XJ)vxQ7jG2S~0%jP-Jmn}&7Ly((^pu69N(yJ#_d;8!DorD!O4SB!8Srg4Q z&!Ynb^ZyIhS}gPIF;5q{Fmvsyc zR$KJ<)X>oh4kr0^tN>h9Sj3Mwo0ecr#lTlF20L6(#Qg;;%ad*+)|Zdj9l?2Ak!wix zLn$&pdGKcQ;wwC7KM3}-4mG)L@kVmdji3Ux2sN39#z0#d2$jGdE3OPBrIxMV7vO1XvqdvelXfIEs5=Ih{^0f)eC@9^#XSkmEYcXe#tv3uZwog7&i4vhf@{i5ZmVypq1FUo-E*PP?6X z`j69iGdt@SYST0xZVRsU1G;-Y=W7)-cuiu&oB0@r-rI(5ypNWW&K50*CEUaNzlaoG zBewety;2#Sdt?QXhL20E!y&X@ACSmH(FRfxaR})f!Ck8nJCMGK51GHYd>-Vxhsbsr^p4AH z@8Fsp@Ybpl?Qeo6oX5^oe0Sk*gAP6ly@u;{!bwi+c0C z0iL1H6YV=f?E5tSaXT#TBqEA8&EnQg^E2xUYo0mEOm1dY%Xt6zP~Ol4tiEQjX=lX3 zNx*vtyHC8Yra73}$eiRbPf)kGoO5b2t3C-#j`r4jlfA}XUGjVq@s4x4($i{%v)Vc3 zTz9&AOUSk)dGA7o*;&27+Dzqt?0@GE_yOwYJol5pWDC4x8DCrxEr>FJ#D!A`+cxQ>;6FPxul&TGL6!GQyv@G4iI>kA6FdV$)`Y<7Kq~HA z8?L5#&SY-@8KN}w6OQGi8OE8IS9LeWG!s=kx8h##=wY;M9(~j^*^tn(np=_G7f$ z;mL}GnQOhf+nMOBc9+nj_zrvl{b4#uOB|xRTEcT5v`gE2eN7_n`X~Fk`G(R{?yNPy z%wm>Rw}=UC2F~8e{gLeDZs(%gfbNHxV56vFPBE8S2d!1sRdWYkYe!-~r@bQHzs~ev ztze&^3T6mC4&0)L-7<3S)x4Ve5Phqnje}qZ;*49W61yg?N-)>hTj{|$(az%U>u=&a zZ2w?qw#SiYT}o8&DL&*(Bxe#GEYs=I_zzP!U5=?!^!Ku;kbX%#EZ}C+0rwJ_&%gA3YNSVK&r69-pQKJ1(^X}wzVE1S94md@x6I$uztQ)T zb&qSlA=;FdUd-3LE9C2jkVosS2Vsx&10|Qjd}R(ZAF$uQRJ*VTCb6fsIGLS+!H0pd zbV2A0y2qkI8%7&eh zl4EOZ!s6-ANi~xv&ZzHt@5#@02ho<+Eep5Emmsy?1)|+9?ku`(40Mm{C2A5elI7NJ zyGO+H$Q@C=Blr7{`7C<$4YyybL?UnV@$K@3uF&nm^D+`Q%1yLr5~rYaa~8D2ZgTNC z$VYB)_d8h}I%Lm=_r7%<&2t$<5Dsih}-_$jnjSM|~9;9kIt(pRN#w)mdf27NN%v5vt5!NLNuG zwM8W}3nM@C>2Eh4exI*GnZN@LbIZ67oYv?gm9#kVW#YD^<^dhp5S;EF)&rDhX0VIV zk+MmIirg7738a@pF0+jJnJPtQq9FRI5uU*-;{2(}>(D>bjrGG zyhcP#SDXK!d7JtU`}X>>`s&)rtk=Wt+ixGvpq|3&{#rdyCM)_U+9e-oiddri7m3WBryFxBFOIDAD)%-y@dup8-LM6< zv0b$=|22zQ#fV9sGrutRgAnT?=y;H`8({dq!rtA0?%heGY95^)*Abb@uWn#nzX1Jx z5WHz5+JCb5HM|(jyqVq$uPw2dmgE$EqXYaIVwDZd8f0;knTJ$=7`x{XU)T?Vpc)ug zi3)B&9_zt{5g_h5Pb~uV7bFsrlblMW&>cMyKJ21!eLnH-c}f=mAAcW&*IaDw9-Lum z=_mOkQM_@g4alvxM1n_Sr%FB1O)TLvSiMP%yblqT%XC0Wrc5wZGw~rb$lh8Y^8Voo z7lXwe$G)CNeDShQPef-u(Tr61)jtstdWkE*J#Ok;Dje* zNe?I6GZ{~(CsCKY*woS+qy(NuX+DM3y&@5pXLt@1nY#f*Fs9+T!28d~pFHgYtk;Kl zYyo_xbVzG*yp(FZuLv`l4k?hjj5PQ!g}HVi{Kbk~wHSBEOEfG4KHx5{ybIkRya*rg zO|COW>27ihZ{QBs{m3&Y6;Xov5q80v=)DSDBQyRBIci>amk|i3eG2Xl)Dm&?lmEJjk9ir)R(57gI>ty3!VLIX=egr^Bu>V5 zh1q_?lcnbO&)FGLPmvrCR;t*tuxiD_&nT6LpYS0(hmd6P8mX3%nyQa=U{VW~z*7n9 zg~4+~@G6U|e5`JN&uFB(Km;R|O0Gz}M`2VHRt%{Qdc^$R4L^5~_>jj;NbOj9o;5dj zOdXb`EWBTO#`w6h^ahj)L65aJh?Ys$8=JY4zBsRWMGWtkn!l7>BNtCERZ3DjC1a8* zF{#WmxPyh?{epK0f1AVrr8ZxxIj<7IJj=D-GdI%VMr!LqJj*+BzryV(eP%L*uNuvj z(jiY$p(M2^(y7Si=|pa&eof+C@I`P(nTcrbXEG8xT=2hi=?U-}sXde52bsGF{vtUo zc`}J02=9ngcZ&2#eV@d!Kky+l8PB@|yj$v>k|71cMwyGTWI^_%GETbEM6gy;i7M}v z2>d&qN7zxG^YIK>OXPY|#b)uU5UV8YB~rmE-wDUPFq`3HM4MsRQz5lvMjzAz80xZ6E;mFyu$K#6P^5u>qteV z$e~p2N}ZcjdU<@6D5=Rcg{dY*crE1$!o~0eX*?C)r#D%DVUu~wl_Xv)Rj#s{CK4bW zhGb>~TuJIAg%33cI;J@~wkt89_8>!Qv1=Tnn_Gyt%_SzkjE}>}mF#d|_!*?~o=I*m2UNB!$HQyAkttU}PBCN!9+M-=Q;qKC%U^}@0skPokg!>hHK9=W5WOZ(a zb=Ddz-UH~Df4P&%^NCgwnMvfsA+}hOh)Q2h4>GdE8CO#EU6+w7a+v!V=S=jw zZVaQBU2y>`r{&Ad~w^+*yWSzS(8~?FBchF@$8AA!qiyTPE1D^Oji~@Iw>35MBAkw#( zbMGZ_vkQzRCpeUu#NLV`SCXGv&P+?j=On9ilU&O8WZOi4XyX5~$XPu^a<4KwQmNXA z=+Sq~@)2U?Ik3=U)fmpv+^ofF@`ew{xA!F{@*KbC=Wvz<#xbJ(#lZN?C6}`oJv^IF z2kUq|HbYOUekAhso;d0&PIT}X%#^G`38G^wiSAuuZ+wZoFCyR50L@*2EA2s6K4aFe zka^q9vt7ob7apAw$lfcwtvT2>pEDQD@bJ1Kl@-_tm%>?Q=>#Rav^!C^c|74tESS5j zLm^N)BZwRSfNi0vn0thrz!=Ru%*5jUnhfbiYR-OPewtAiHc;&)J~ox-S`Xgf3eWos zlDP+~d=(N|0i^0M<1e@h(qd&j#3HJ|tB+y}9KtraLjG3alXcO*k+rpvu{6j`b5_1w zs2H|aPhFn;?kI1S?qawq#=NKoz#g`TINnrPzc*pKz+#3a8$*t!3EibXBeU6q8nc>Y zEDD1*9zosIL;S~Ik}?F6yz6FHd!gCK>JX6_x!2yIuR5KXDZPLIOm@J;^Zv~c#i1w(&>VC-g=wYU1x`x4YFoyj}mjs?Lv z(HZ7VCj&E_h`~Cu4xPm(sg~qU#xOsl+$Geh9HvIZs05?;ow?iEX6>^cT086x z_6c(x*1<|@&OFxPzERPvW5t_m!LZIZkCRc{Lj>Wl7wwe@wn&=g90(myu))DqJKF!J zuc&$sT6H5`6^1)0g1KS1e?bPnmeJcxW5rmz@F`k?iug>Y^H#VsiBbHdGwc6heWxV) zHv-&k2|W-5zGF5cr@znk`GU5#?wC{XG9pw(vR`A#x-3y^!MT1gcS`peqA2lBo1_S5 zi)V+{xYOKfMt6Ib?_bpuol+j=Y|o9S`(y=gmp9Q}>@70NQCBt7DrwdxYMWer>*a9D zyC2*qu*0W!A38fdI@zf9p`pYyt{8*OZmKh!riZK;|9`#>R!j4L)?G0DWvQ3>O{yW0 zk!!FCX9MM57u)>XP`+S7;5WA!p5zDbcO$vg(duNh_bPagbd<4K=W>&I1(Bq9x1)PZ zZ#3GP8*SS@Zx%BDr|eLi<0CHefoRn)&OE1(R|ya2UtKw*$nD$a4o;e#c=^4|lxAfj zcl~^G>=D*-FbLmRE5Ocf!2{Wa4KCbp>9G8}!AUgGDII7YJmB_0TfH<|o8`e{|ET`( zG%Suj-OTIZnr=~VB$(16#1wOy>nzJ&WR6nZ@kRT2OPu~reP=mQnmA$`aUPYINQ0j} zvI6AK3N=XC>Ra;%JJx6V_FHGHpw-KsZzZYA#6%17L?f{tc2Z+{Ont)HHp{yd?CX5$ zcGbhYJ^HaROja4Tp~LK{SGqmD2!8Q0;Aa}%clw>4iTBk@B~ssj+8D=Z zqwZ6EQHyGWqvZDUg`&Ol!4|Dd1pKvt|H%61N<#!T}a) zrLiWMBjGWtZcU=5ub4FxKQ$NiY)#Gl<}pyuhwuUya!$O#n+p=3>Pf{{J0~^rI!pfy zTCzPKo$*z>l9^};Huyd{hHD_;&v@Oal<0&+4F=tj&S+p(wNKj0Ze|um+D_^sSP{9Y z(kQ71)1&r^QyjehL*q3act@yj+2f;)6y}#;)<;s+a)xNaM72>>2VFD3YHrOkYp5j7 z##EecZD6cvt>+U(``7u|?WcbrXIWS!GpgucsgS7U^`Tz6JgBv+UOOtfE_$%=8%yaT zwHGu}1YSWVB3YBbTK}vpRg)@{;kv(GscWO#E9#f@{)i&Fbr)?=Ih0?ypq1BCo%Gsd z^+5NGwi;XYiE;i;ETbjWB9TN7j;TAG;L-R_(vhZkXrBIz%C^JKJR-)HGt{*}a|Fo^ zj=?&~07p+}B+A7*-pdKG0<89E?BSV4duBZw9Y#M<^DPay6uuzr!qdMwXd(!1>KBw{lY%k&;{vyD-W#-2;WlKGVkSV>Oodg#@m zSTTbA_zxRx6=$k&6=cL?bMZ_!^KQXTB%tehkk4F$1$NW;lsgY*zBlqrT|nW4sE5l1 z8}#RluQ|x{6hs7`@!HY&l!vIpPEB58EuF{CgF?y7Y!)E@nigK5;>7dv6LU>Lg+ghf z0X|Skx%s&=bKQ-u&bvds!G=$;`&cs+9CCUYJ77D=xX$Q>tYpt`>INVdj;g1~QyHtK znTTzaE0mJT;2WS0Qe$nj<}M~tv6DzhacstQVAT2%5536xMBvpQXYParbQ~6BaiXpr zu{UC{*z#aa945B$lvBGaw$@#8pbv=4cEz^X$f~yuXZVFVRM-;EV+WOD|NKfn=#)f~ zW>QhHjoSHl*nPW+(qsqUbQDW59&|u^P&1wBzicCTrpLb?m92A_br}d6d#k}rFzJ3RugNPid}OYhV2wo zfs7%Szk_$a2d}yTe`7dS+Bj^_SzsTQVdz=x>>reFegXe_VHhy^$h z`)dx7>YI$>8?xw~$e@nLLL3=NGNM7OE?^DEVQrUE^eS}R2pNUK1u9q z2=?Dux;CB%E3i}N1U*SkSVa*@7>d=n5VSg(Rx)x$i7PK9Zd5=RD8RJ%S(5`u{xj@= z0dRWt;OFw-n+9U(o?<*LiEvyGoiq-4v(+nD938v?ZM4!$!Txqr;HzLrZp19L$EJLu zZ-7gPN1k3{D^3P6AT@b?6!=-Zs|?0Hv!ec;$oQY&&i8_T$t@WiB(D>Ufm?{U_r(ub zgCq-Lr2v-ikDyK}hED2lvE7HN8(4EE^le_(1TS(0r~OZ$Yib&~wW8B!kWK^(!3yN2 zd*xD?7=n0NmDN0?Tsm|f#)cM_x;(_3Z;`>fhCc0urGK8N<6MxfE$~Y|=(FH;rcf*3 zX)w>Qc`au*2>zx%eoGf(i7CJnH^%Fs(g$o&1AKyWU^=qlcTM5yYtcI_Ct&X6XYGQvXj1G6)bbMq#iMKM(kspty+wii3#89g2| ztFOTw3m)tWwWI^_DKBt(Od$VWhB$IL)@CL1kQU~%5E#hj=z{X#N)B;_oFLoZgAKn4 zisu?ApLd~=I!4tehwu|VUM*zn1v~RC-pUnD+I!dx6OEs!%Wuc?Z^q~70mdhfdZU*k zUmn=3dSDOcva^q&OXiZ3{|=tJ!T7s}xzcL9JVX?K~-YfAvVZmTb_3*%( zlQZnWX)uEM6oi|wVwv#n%>~!6g7?IO6&XSo)v93X8-wPkip=~&^gkafAaMyB|M@mC zmA&|+7r^g|_x_FuKusI&Kh4_>9wr z{s?G^<={Fb+H{$#WW}P(!;K&>r#lzQPNZ4gWp^TEph6#MvJ4JK<*YaYv7+p2Qm@f*^fk zBtjzWUIAuBIN-7%SrRvU$H+2a^VrORVB$>X;|;G6p0#Aml7%dJJe4p2$MaW-vj}^W zuw)5CmheJJC+QGp!w2@XA|5A^B40S36~#}&^ZSu|SfU`py8D#>r6ZegrOBBRU>1c_ zH^5aiR=co%#qvJk{*pMC#C(LiSeT83iOYvp6LvWnlXSio_AlX5k|>%)!+eZV_^X7& zOJZaas}jc2^x6@E40y`sk(<9LG3xP@JDgL!+&j0p#n=6=FQCNWFlp_163 z#7|#w+CF8C?hJh}3r?29XjSG86RmA>^#@hh6D0H3RE( zHG9+niM5i`_>Hc?y2bH*4`yXAvNM`jPyf>K6?>0L%NVo*{W}>&Kb=}1@>=6Q_1r$s^yUwNI})Zjw9 z`nV7_*riy9>Fs;~ z!<5hYBeY)qYb~(S*{|s}k;QC8Ke&Z-1nC7Y#R_tv@%i+U0!hvF8U_*?j5X1)BomF1I;T zjUqDFfP8p7(YAB=OH*LAjl`C&r+;_vBqk=cAUoT}t*f_MTO&sKW5H4tRVPDzojOTt z6AK3ydQ#!>k80?HsJJ?3kMoTMB{th!?Nj!@oTgKVo@td0B;OTtyB#$1bAGQTTiaG=rgpweD5pCy zv1(wKn}9VPsWRGgBg#aqHfQKVZWp9xXi~$Z8BSZho;|WowX*voSp&_l@tGQ7*G_O( zyOH==_c$wS@eymx)sLL&Zb5Gl9gthV+L{h7hrC87wb<%sd3f$o=27a-dz)|RQ4>cu zk?ZWRL+St($7j&>8;Ju{pcmhCkUSB=>w(N}Ww0Y#y@$pdFm#u!1;}Des$hybmy-?$ zJ9@9YwBB<4l{v;L3oFnoIALypcq*>vdrA5a?6?d>VeS|o^m?a}Q&o=)755e=od|rP zYWn_XZr2Y(C++F}z1A5{>9y8eyMsB6zDY^8VW%?(5G_1TOc5WE+OB2h?oe{L6>5a~ zc;%BG1txkgs6HyGQ>&%E>=Bn$S+F_p$w;czxVHr+k90bW}@@A(SWoBjUjR+mr;T|xW3 zzK#lZb(Z0`mLeuQ)VM+SyeRWA+4QSw9DGq%yc(g$#H^|GH#Vt@p@Z%!XOlaW=gs28 zJJpQ@^NKl8JyPG;{rxNLNuUkV!%|R&z7-kORP&gX!deW!T{L`0SCW_- z9;RdQaqEPlR3<9ke=|zy#;zC4;QZipb6s#=70A(lZ@!_kOBXA(ebLV9+hET#AK{hW zfzd4o)#?L4f%swN>q4|*5z)tV;Yzfp?!kZ?=oZZ6QX@|Exw-Yo&TkVJ3#Fw7YZnX| z33Qo!>K4-`Ym}K2G9MM_KdOyJ6Y%Oeh&vrY(?7u8?M}SFrkXGb#Orqb1M#J2;&*}K ziBp3?loYq7qroN4`$mQt^KA01_Hs0zF_%lVY z7J3o`c#V%g3=8Bw=l;)FumMmb6{)8m0WNPb^-wY9EOQlT+gO-32C3vkisqmt22hQX zhnhi9yrB46VFjcGommK<{|uwEiL>sfU*l4${y%t2=@)t0YeyB%Ks@Jt#9U4jV|k6e zVPXf=C2r9)^ar_w1n|NAyp0}t1@c%gh>5*3_N%n!O7pN;lB%#JAS0W=2=gV;qUzMm zB`1n|Ty0|}%Yz~*2rjx%xL<7~r(!X(3%5bnR^!C}is;K3&ZQ2VA4S2BltgD=_RfPN z?9cuyM^)5soYm67Z#$NYFdL_(5@-jk2TzUfU}P!AsFJ}AFc({{F02?|m~E-q3!3Y# z*7g~@mHoAq66Tlx3=3S-7~(_K)L49pe_)*XLg&>rv81k{H8HK|4`&Q1as12qO`@m*xh*HE|^aC8>>GRdqrTUs6c$bqxl+~SU#la4D$0oaO4UmmgMAzE@E{EXZ&Kk^;@tX zuJb0r&#?<$il;EKEFnhs7rBE$tln$*qg-Y%7M#@-qG{vs+0&!vj)7}D;5PKe>E%Sp zGIDzT#ICPuj>tKa491*dIyrLkg_p;B?p^^g-2ik?Wvr!TdOcNK@ksMUYVDGTl3`I9p)d7uH0eFB zD|X*C?;!Zu`f7~Xz>2a%b~9feUnbu@I|s5M(T1n|= zCtUzyh&Fwue+L=u(2;3{cb9oM?jCh*qClgG%boV#YEWiGk$*zY`|68iR9a(?zScf8 z>M9-O^>GV$wKzZLsP*&-tL@unkGEZWh_9$`lU>4YWK}S8sBU=C-=S{?!({Un%qi*F zMQ5me>_^m~FW%=d{n9J#Ed=BE&Q0sBqSkVt*THLnHL(!Bo=VuTFNh?@qnl5`TvCG^ z;y5}4MiN!6={9qly7Rry(KJ7q9j*ExcqiG8t?l-{y1wOhCHn&iF6s4MgG_S3IK+;w zXC6SeS0letKwSZ8^*JLrqkkjPe9j#Tx_6D6hF-FtFoGH&^>=zvx-Og?kNCL59K7PG zyXX^i0m_CHm(c@};ai>$O_Yw@*i5UZy}-`wQ@+3K8}>X<%blzfW)ZUhk?Xfu*Lz^6 zn1fZhk=(%{B=kC&=+__-Cu9A5L$+lV9_^VrAJe_7z1ls z-Y`2xv|2^fWhxRq3``bm14vU9IC93)G5aNG;cYMh8ZEs2<~|kt(qAx zpc&OA{fXb6*8idZIujvjuiBX@u*7EZ+1qMC9Yb~Nb2y69T93`|%@F#uEqXml!pGFY8URCAQTF`|vn-a&Qcm===w;~{|0QuuI#}Y-WybFoZl<2> zxx?OW*oUsM#;?c)-(=ryBnuSh<%B_CmxfIgjZ=nK9|0LT0uO2p*u3U=)j9Czhk-k7 ziC6`#N{J7UEgpnuAut2DAE7dR9(Em8hFY& zT*pq>OAci%$iq1>Le1xM1G?@qPgx&Ncn5KKP3$xVyH~o}3WiNO)m8!}G8`Nu_;aer zn}F`zL5%&F+Q!aoKk}DK%*PbYYN^jX%uE#HUh|1;Yy|!B z1-rWjIfUYz+?6;R$}y_SjOrWi+!++f2qGe*iG?m_W)2ZK5Ts8%`gMGdOwA`^`v=v9 zslgf4hcBoR-Ja|4eSUn{5?GJ@g|HnK_IaVECJ3aQD{RU{%? zm{}+YAC!;TF++)DyAnBrGBBR%oZl0O>n~!wyNT=zqfP z(wzCX;V*uPwA@A}-(xAHM~ zrdq?k{Flt!R?y>3!+Pj661@XWw39OclmMd1+N z~tpruuyM-<$5bt_(^tmMJ(;jSd__G<2uX?EY4()ek4QKh^X10Sb5Wt;(5GkAlKbR zBy|tDo!?X&di3_NMuNh>VGc6ilXt8L3(i#LyaMOXYGR+md9K><`TUCa*jgpQeVE^T ziy!5B9r5y4z}a~V&3)eMkKebOtI`{Wh+jPG@uP5alGUD#UHXblX{In2PG1IJM|7(x4n_JD`1_@9X z(j{qSLivRKiGK!H8)YKqCo7eFa#XxM)-b)w!5m3HCKw6V6Pr1mL*H4;eG}<7+T0qg zhEREx$F1p1b^Kl#s-q3E+qH<%>>+2_PB-_aQnzc5i9G>HQSRB9Ct5pSiEfs5neNU_?b6se?H=25g42e_US9yOjv2;lJ<05lK z&5nHP&+Y4AuJU|IrQY{=*E8X`^SiOk8f<^T)0DFZnSG3^x|-XSx|Zc$a`yL9kSe#y z^>#4h%(3Qeqm4H&(DFmf`{{}0y}VYVh%6CTe0%(sPQrX&4ADk$EgmhGR2YBN~YxNF?niXGEZQ zU|O)L_gL-m-HT`*nLHxKml?jeZq%a9qH5@C7>Z7+Ebu%FLvnR|-uy;4eSlN9G^hJ9 z{MNO)EqniJsG2)BNhhv!e^(WJE&QE)QFa?_xH%zeAA@@XpF4B(0ael}VXh_L3A4A3 z0{d@}i=G90@C$6a++^X}f~Ow?c8`)zvNuz`T*2mvc@r-McZ5E*$N7i&i}*^y=~vhu zY;97*7+-I)o%6s?Bv2dhEu5M?(F~_Ut>NQsjl8A?zxD@_)y>FoXDr~z(7|Bk4;S8j z9*FT(P4zzY?&yuG92~lScOjKgLz6xYrZblL_eaL~*67i}--AoMc(^QYf~4vd8mKGPJe#RR)-DgR4l70y;_3|^X??UCxwZ27>mm_ERn^}88+prOKQY&Xt zb$W!Xbu#lEYurbrB3@L^JE8>{e}?{ft-S?$BoUI~YIbO*yOP?h8G4Ml)jnvwH*TUu zBZ<3b2yOOWxN%-bqnVl77(#^SH`TygP7mkXRt1CUs z>T}KajD8G0vM|)QAunf;x%ip9MrC!2Jj-LGtQ?-fB&tpOf(oD#OO-S0i+8CDAXfnWrcQODeF{!Q#>E1p=8nE4zdS!fWM{oO_v>=8w5qd!*CPQKel z#aTSLI!AxvRi!$(n7(OL1JU;b)qt~LEw5}HGyhe><1mxiJIRS=@`QWvE~=}wj46g( zkB{i`ChUf)Aaj$2s^fz#^Bx(3*s8B;>%v}UJ%GF9)~n#UEEDRh;>p*x(e;SVjw1@X z10VdNEC&ogB7M176Ibnb1JUK>YGKl@)C-zB?IbAu3rlbZz3YrO9rVWvR zC^EK<@p-kE3>&5&ws1#1NslLI+M5_{P2vPIVZms}>DL?EVvjKxD=w>w=iEDo{O2}J zb1Qk@&hBidzk5W#g=cO$5v7&H(LMWHtFN&EY}ZJmjCoa2kAT%!M>WA0=tTzXxjqMq zav@pgo;)K^q zpCt?Z4l5!DD1(01274tP)>|PbbIdVjTJ=AC!Y83G)!)qf72|i~f7ndz!H#{6#}!B1 zWhEBRLE1{6<&P+3+pVE$;gSIc04x)myqS6a$wNR(%$ z5l=Va?xDQiMjd0Gv?9$z+TuLQPt3Su=(RUVe=yF&EK4L1mds*CRyBc~csX!^nTR+= zsCQVvAg{nX9l?)kK=yelI%0K-Ne4|h+l38bF~@kyf5SEM+V>(`+f)! zOyS}XESl80Tt{Os<3t+Fxhc8z)7hn%|aGH$g zneH+Y3%ePdED_31pdWtZr|fvEE3sCp@Y{v#ohMk|l9vxL+T3JWA2W}$(KBBd)6oi9 zu&}Ry*~!9a`*0RUkoi8&&qa{(Iqdj5=&nMXUyr%sLuTV=m}8c({xGpH3*Teck7KRo z6H~ehI)5`Wltd2tBze%fT)iYxvk9yCDV}2o##V;xNC)Dq)xbTa0;gD;u}d%A+jvs> z@emKQnzhl0bSPwh|4e;BEa(z>B__O~GYI1y~-g zQ;gjIEu`Tku@UJYRDnI$9bT$D=!Iis^`$RVcA^z|_?p10q)O{9`&>BvGI6)f>HG6^@ z+R2%A2!BU9?ETL7Qr#jIN`h(;Ou`-h_J;o*v?o0anB7ugAFTy4Qi1hPOLV0mcPPcz z9IR4$WJ4;^{Ji@<&-(}d;8te(H|})^**b+Ll3GR?y>vj6xWXeo6L^MP%u+!QVNjc5EE-+J4t@xCg zyUA~*KJqo6&$z2pElIsr60(ts`{g7XBmK7Wakr11wNo*h(d;1U6&PTA;uXF@qe+)N z!R$zv!l&V}OLsNtXcx;ql+J#_&LtIKXm#!+ecxPsR_PWeJ>#U-PVOKzm05U?;6k$T zvs8Xbr$>iz34%uOMYo7UUBHgG!Rkp*aM4wFxuW2EqL7Ph+*Pc<0?d7GMxL3gOBXq* zSd_X$#lDnkJgL5u=a332sfM%ojUZ5jyGCjq$LS zViNCr%{%3}q`$dT;0bmsfM$~#Lg_pxUFRh_n1T0755lzkUMeZ2KU^a3kxEMGaW3;B z-Tb6#?j=`#9sXZ>xqV=)g5;7KK&cLuK8b>Cis6dskSEbjQZp=AGU>}HcOVVUYovqS z$Er%H^^`h7sTP!#xWl~PXWpfIp>%S5%Gh6X_P_IK2pu;T5Bo&Vy3#n1btOWz4zQ z&pE?;O=Rg~tzh!-)kKyA>0~jBQb{O%HYI8s;x3~1q$2Yn-$@m;R0Y1`Nu)2PMBV5Td|d{wDf6FHIfkUCDe!b>DX zV#iXuot3M}UXX5=8TpjC6ZTfwU&*+h$ff9J*`*>Mg5(lObhy&TK9YhJ3-KGl%84w! z4nLDH@JWSt0w1!9e(oo@wq#sa`j2O3m2RIXWVYn_vN4kA z@Y714L+MSLnROJ66U)1VGf-q*DqoYh_EWBW4K4E*XX6=8#B*V-c@ZhOi2fGNMH#8| zDwSI17_K5(x*(b|Z}?7W(LNx~(Pr|0PCipJ5W=y0|dP7EX7K*Nty3#nb`hDg|ddADOq?TFw#7d`EktJCL(E*|v zKkfjLSveDAUSx%&ieF|-c8?O%g6yQ0e<6hKPgog_U<)0uM$J*O}O0GM0O+ z+&xxAYN+M(mc4z6bLk4--QeRMAMzKeS{5XvLC#V%l)=*{5am_OM=I_nJ43!^L_(z> za16U9cUVqyGlIN~K=!cIY)i*csmhmXYUx8NXV=5<3Vp=Airy3~mz-rpRl++=YSE=D zvQ)zhvw?Kd7I}~^q4FtRO>KUcntO?U&d99D*&-F$((zZGHN?F{(+gXj^l^>nDMhEr z`SghUi}VU&_D%Tp(rH)Db6M{wu9%LyntV;eT_U*u2WCWckLUr>Y9ec*N0WyoKu$}M zYT5g8-pQ)H;IFU4awlDIrT$(R0SKgVPdQV2xqbvI zC2ZQVt1@yoIgg@w-5W+Mv*L2c2S|ii5@*pXGHx-;BO@?rW zCkMZkuBe5$YijQJ97MJ3v_#%3mb+wb9`YR0n^-W|qP?H7Qu3sNI+i}KVtKvdO!~O? zsoCF(J(H5P6?O@+JVe)IVZ8;5ELHPjNhN1Ce0-JNCA(100nxIu3+1Uo+{I#T}<#l@NxSzu+GAeFR~?lhQ+pf#t6lp%g)y*?ju@Ld;!sRV(FR8s+@kp z79lpF>~P^u5PZ4pCOK7ZU>yqz`2pWO=Z<0pNnc&j7gEb3CtNi57F2u@<|#iht#Ai?jd_m z`s~URyJ1UAw7VeV<)6g}gdIgRz4X9+!h9$3RqPF^V!Ow4+~=Mbxw}~AA}@la*L(_s z`!UxQ+bk>BiDajI%1Q`IyC`RwXdF4)^6^zH2kJqee~+3<|r;5X85 z`!@3^{=g%iNvx`8+{xuPVo^%Z?T=oJTsISYB|G;N=@K@KSiYuWp5?@n(^YsH1j%pk zv+R4ZI|S`5Pj{cE6MIAEKrG1Q>}=^S{e-<0&y$HY{Wh$J#5xvTZK1V4Wu=OSwL~nl zT!I}X>@_*U<9f+8PjJ%zhZlH_PvLJlh!=Z`bM7o3QpNR%9V84I!rNJdcUQvit3}qf zDsxqs-)3YMWe26?0qThU<)8 z>>7tif!I?pJmJZUR*@4jANQ4=DdCIKpW$D2!E2_fv6~cP+h%3tOqt+^XCVb#t z(gFNAuaZvbV(UmpXT^0s_Og!Tx3W`3E@bD3_nj%McSJiRaUEeNN#b4NQHVwQ@%#|) zMP^(4LD}(Qg^Ew)M}LY%E$b&1%46Q^acyDLaEO#ea_7w9Q5azv5T8S?BTUpH>oPLg zw{k|j=6IJ~JarVoxULHGV7z@mHU49?7ng84{aMtTU<7kU6{`UQ_Yg z#Db7o5Rpok6%+f_&wXvi@saQO7Xf3hDqzAe5+!mdmoKZ-=zNRo$W#fv{q5dN~Q3~!Y zUYgYQ$jSN9hLY+f@odC*PQx6D7bz{Ap67nf8VK)=urrDM zkiZOoU@UT~6ye@dWh7c58TveLSj$lC#`UD)NKQ|ACW9w`z*7Yn&GWDXNL1q$^CPP( zJM^PPD##tFAd}ULMQ4fTlz#RpxP$PxB;)#W{z;9MoHk-NiM1=Xr|7Ty=(d}D{dh8D zVBTeoMb0u4K@$J)6J{+hSCiT{;ldJ@sN~H48^$Ac@k8D#5imc0mxxXzPa+nAoch8k zBvAtK3*WLjvb%)kODc3^SAMj=B?=@OL_9I65RDx=W2W$k#WoD_TCp2NQ^*K>j8k@?Sd7n+eu)uWWo7P!=iwc%l}`7<+T?^+IaOHC zME+kc2Ko)On4fL@lMeE7jc; z6b%%Ene4K`#u#H8ob|g4R3Ojackem->|yP-_c=G(u$6hd&);EU{s%&0al8=L&J*aJ zKIGi2vB8$1=4SR=i8kwz3kq-EynJdnRr+k@r zvtbfmkLJnV#=4r@4NbX0YVP1^OY%EM3Dtj}A`TPz3XwFYR z;mV)07IyK9MVs*v%aPRWXrObDSj`Xl{9;(`JnJi0JrZqjdfeAxQ2!-$mv1shI0Lg& zbbc@Ie-sY$_tE9=6W#tNarsHEjD6T1R_{_YWG-IkQpQcEL^_ynHlLj`$K%@lH`*ibV}7$uKg+!f@q&dE->I`YDdnHGBT&m+39#S(s!;LEa!|e zD<@_+_YRlQ6R`GUh0B?5QM1S+Kb_9qCo^+8aw--*pD~ZcuIb5GkN|#=2f)z5wD?jM zVb|_#UVVPhviba79(ig&O^~H?w{|0)CmBB-dX%wPbL+pA@2&hsR^3TW))-HFCcXu? zOkVsco`E-$$3y7vVmHpya`qkGfx!3TP`~nROCdt ziO7b3oz6Q*Wh}FB?%m_u0TQh*l@a3rR`T=R#4&k={9HX?Gx6taSCmzArF#^cd_o)glxuhE`Vc?_m!J>SWX?&n_C#8WHyOnYdZ zZa0$misHPW6CLHE7$7)>w-Zaw3^H5H?-mB#;Z1Q{=kw}gnJsVfIP*FhT*Tr<6VGGV z&zztE_Q(RrS#%but|S6n%e?Ghm5E);N-quf;d5r=RcOk?y!T#K^?|K)rJXZrnq zxcb{+m3cnV63TEkpIx~V8QIBb_IR$kkiQ)n)=Zo~m%G?sj2Xi^$)4=}-OW{|;{|U; zB2H&}KlqB3XzruL{m1bk_wyTjXfb75v1BzKob35wWj@b(c!I`aMnF61EJjC0!Am=z zOw@8_A>Ke{j@K;zQ+$90R>hOWVW9c3n~9$H^MU7joNJ9oyG~|3>}CDiNb6Ubi+YTh z2w%$oVTOtLa@dTo_xatR7rvj&JNQ%b?Rj;uC|r#h!ARLxd?+6fBev;rM!=F+^1AIv ze?8aat@x%#(Nj?yrsAcXR_KY7G)QE7JLnmdGo5R~WHN4=HWlwxulFvpcj_O6jvupv zXY-oFu?01BqZ`!XxKH%Q-#%0=cf>J!l~ zXE5ReA!|NB=4-{|a-y7QA%Yi?U?ZS2=S$)X$C8t64BwF<#3}L{$!7eZOvdWm%}=n2 zxwGE!T<=`2Ze?JN@^`W-H3YsFPf>5~9Mg?R>shY9m-oXnM}tW5Y~M$!4~8{d&kWs_ zZyd>tL|4q9=;tn~13bc+SZ=X5+|vB6jBlB>*+>>=j9a&^vRWDS;nb@)A`3HCd%?$U z1~Y8uDz7po=*tP6m?ob4P^54yYlZdto6JR& zo}MB0b6$(}@pO{$Ty-I`gUq+{!Pgk&^=OA20g8t)F|5aPf0Z3b>sUsG5r$UOJJ=wt z#A@LOL=#%9J|l9x&74@3z49WYwR@1!Wa%T1Jbp0Wm*Z2D`aD{>m@BugdNmS;^yK8b z@v!(O{z&#&y~9e9_| zv;JRasawI(VR)kp}j9HMXY9 z{pXAt)6C1wL>e+>Jp`(a?Ed0l4U4%py}`u2jPJzQ$@y^lSg^x`Y)&U8VMtl8Ok_JU zg+t_+uk#rLg^TvguJ1EGoRO0_o$R|44RO|~8o+Gkfjytj?4V6{F4G*zU137JDa6IP zX(5bPOW4TV9_Dwn7ZZ)!*v$IEo5yk`eB*3Jtw&*I(3hU9iv{etBYX_z+1krj#S?$y zkF557EZ|J;PlH4d{S{8-#UIO0@%XgxY33}?A?4dy&(-)@(dS)$_cB)%sk~Okr4}5vUmAlJ-opLN!!AYq9AB_&k@MIW|GZ#5CuAKjI zYPR)OSEOn9FcC#2IvM@h&2Of2E%iw?Gug$Z%nJHC8?Un#8LAKAG5E^uSRZ>)!J3a; zU*y`nwRM8j;dS{E4qZMA#jpTtERtd`@iTf2+EpO;;q9C*QnpbQ@F4fuj`VeBYy@pU zE%GuP2wf88-o)1No!Hfvu~rPgR_3XCL+3{ZG^2v0^6M1n#at5}8I8s0sZpD{H0T#@ z!x%R*elh7~){HK^%RD@9cscWMZ%>xPSuGE*#)mnjm=0qH#)6<#fW8{y{%k&9%1j}0 zXKpvw;K4Cow<3?V;8#r6a@NVut)0Q?Fu9yir3n&ssC3AM@Dw0M@$!nO6h~#K|hf={xsiXh};2!)D_iyO2uk6+JpsK`hel4{p2LUEWVOXH7Ae-KH{FUhIOU%_ z?&jLd`RQh4@-|<05))N%pvS#rozS^X8&6U^8$G<3xx-#pB6-*y_c0&+gQ{Asa|e|m z9A}^+dPP_-HuFd50X*!l+)k_ z@s~y~>w^zZ#WKFhwWd>Zp3QZy4Zp)l=xEXl0CBoDCPXg+rthcxZZ%iOYO^*Brn&;p zb0Y84F(JQ{^})i&qFqb5ruZ&zlldPSW`Q?QlcBjPOt=M%12o}k*xv`k8i=c^86qxk zI1$~!Udaj2l_G5X>VpJel8@S$aNbkhAyIdB|7PQUS*3KzJBG7+H3z za;`!*8n3A@LKgHV~d@=?gm70i4ppIMKrUx&(AkRM*4-A^z(oCV8Whz|0D^Z75g!t}vz zG)_!cIpDF)1wW?)4zh(5-{k%(`WO9pJozwC+!9e(OXm~x{;?uD=9W`SakBX@-fzNaAh5Sx!04~v| z!6rv@jud{$S#Nq}Fpe;xi~ysh)(orh(kd_Nr+%6bHpHx*&vn%vNN6til_}3>|5Eu2 ztSruerowD$b^L%QUts5)dZ=e$IWp8ctk3CewB&4ZC{G=piwDI#pO2oL%v|vG&i|9C z{Sd7XO);cA;c{#o+Wj%(7OC$K_YhzBWmXQas)8KOmCp^**SUrbk*ml9=@5I=kt3?9 z-H`1_m=S!}k&*lPOIb6$D~ASOFXK5qNcCFo!E>sJsIxrINY#a~Me04G+G@Uo@!6;T zxb^(T^FncdytTEK1>y|UoOhyibX>fJHE?LUO;yM6E@$%dmqVn*s*3pP1g$jptbx-SKXz&vgSt8XUky(6cqUR1YoQWZG&WrwM!&tP;OoQ!81_i4N(NLm zRQ5;@?&a#9vMi&7#8tZ|BM-UBY;;P^oxgn---2aSJG4How;x@=_*~2D#&Zw&NDg(7 z>zvJ+@Tafhz4mi;-bEc#+uNjc1X#yFoV%9d!mF+=FO>Q*wk)nSd{ zMxGL1O8fTWZS?WN>9B^VHIZwIxN4{u@>ONTN{VTa@OGptvSaUYDDAms2dxi4^jHwM zNUqPW_#4lO;c>)x70msN{vcNv&y0A4(MXXW934i(zv%e4yHQ35-{@7k7oYe(ztOj6 zJmc}+@|pL!J6;gaD2~cb=_@PN-6>;fca}QzldR0~yb@m}`pc#8N5(J{Zz4u|UJj}0 z1ry=a5Y<4=W=?Prq$Shi-N~9x&=Z!AWs(1SYPpP*q_%Tqy9JKK3(^c8@q9+kiya#J z0(ouY+RPfskKj4zOQ#H5A$`#c7j-DwS>Azt%L&^VgO6iluc9f~1koFRW?bS6o?D)& zckz8HhL~x%MFdep#jL35@$tMpc~0l|Z-$(KPq4>DRtIbFGfcr=*u}B z*{HsX_uJ7b(Oj+#dmYU>)5fXH20rGK;Z3r7mT0F7L*@=OJ&y%JL^4KwM=}!YPfx|k z@+L>)n_opT7$^HE=(vbzE;0laJ#4OdE@l-^W*l-3*n~gbi9BRjJTZS%Mql5(TvTkf zLe@dWsyv6f5=_E&N#1DqEqx+bgU<(BUyO&8>FN8xkd()f?aaM{JKuJ8hS~Q8se9Z+1%)WHh(kK-M z9ZVvlY67Gt8d}rO%1yaSE;o^fK?0!5HaMK0`aZ(MT0- z^Tp|#<%{48j2t$Tg+Qt59rRvz(HB{vnS527d6BWVGaUwlgm!X8S(+|z7?VeZE)J44 z@K<&u@euGW{G$d6b7Su&<5%?VdP12lo!Lm&Q^0Vn5Gqc<>#&I`G}m$+{RDbxjc6{Y zmHc#wezdt~8JDWOO7>bL&>EObdwuX)PWr_{vlo$4+&`YLeB^p$Y}S18`^-*+#?R=s zSotsxz8n(UAEZx~at&7K$!nxRcU6`7ymod$(ay-l+(N->?>Y@OGb?>3kR|+}4#21K z1N@+_9n2nX8@Ku<*OcvHIbqq!!IS+Mt-(g{`MN6gY}Ovg@>c$$N`55V9Da^n@%ksS zuIxh%P`9GkjxWW2or-=e@eTo;O+Z#&Tw zaa#qbIr^#K8nVR!+lfc|Z1ZZqTL_XAvFs%n&F|XTYt`Tas9L2C%O=;*{|~FU-jjT# z{cPh%#&tH*n~StzdKvI~_PdS+gYqD`(b}jZMTi6QD(=&kCWkrV~ z4Hb8LLCln0y~cgf`rf{J_Bk6(X6X}o)$>>wK2t3aha*E&yaJ84 z$8#s+=06rcTp7Z}=&Mm41o!hs>sc)^fqTh9CjW}W_HW58r~Ed#3PV3`_)7F zCUUS(=uECy-b|Efuji9!{PRedg~`9oALpmDQ-_u&4|tIl2kv`hf+40&ybP1tFzVl;ji)vxenw2L+c1r z*B{SlWCZOK76~_k;`PGoDB#IkG3N2{m(Oz#RsVML%YC0m9<4@Uo<&ey?eNyAN9j|EwaO5!b`H)d+|^zzcM(?^ux?X2Hn%&)k2R) zFJx4YvvU_dP%A6HE2DdqpPxpC7^S^P@nx<=uYSsCNzz!wMc8mQYoK?7Y^GylGG=+Q zEWtD9qf;m#@CUn%&cL4doRu zH2$O2ei_JePSR9aVMF#M=m5bI%OUM|!-&!_`#AV2)o}K;nlaqSsMz^rp3b01TE%OZ!o%jJ^uma4$R@PsgNG^v(;@S2-SekmU)yClbdSo`IiTrEMN8ZRj@!w?M zHeGv_z1A?|zvU{{cP_JA2!@m6W_Bhkip$cM2nWI_ zx-no#t9&?mWexCK;Zy9ul@qoF79>@H&okr;%TSsNd77oVHcnql|J2^>_Maz_t*1E zy{_AXo`@q8S@o^xpX_TQURG_@J9Q}Pu!9+88~i-xPL`mL4wjHNixF6f?iYNPS+NZ| zM2b=Ryb_i_nk({=?o+w)rD{LsYeZJt%;lgmBHV^6buSfm2)1drHA#`O>IiQp`j7{S zy&9qq_6c^opAi%V;2e!+B6tt0eQM|{z`I#3v%r;OII#e&*|!?%*$#GGJdM8jK{V*di(o`m(AVYV^LSMpgUQZ6a4!qM_<<=M&ws@8YsxlE-y60IvvPVeY$v_<`( zQB~Zq&hDkYpgJrX(?0skXPUc=(KA%se<2^%fz&b0@>)+vWh12JSt&*KtVe}`oY|D! zEvgrN@+*umooE0#zRB8HA9|z~DN___)Dx_+&Tf9mhuW*$Le_0Rnw37D{6;tBXPJlS zZYOl>3wqJTSGx{q78C;0i2^%`?|M@4;p)XbXJKtvPg#yy3NO}(B2%A;9;#WuWAM0wHk6DIzr>0MoLymB|!xoW6uh4{0WdtfSc%J5qVzQ19 zk%RYAPm*)1$9g(7*+Z0kul$GP?Qg*vyh&eySP0dsoT|v$+aea?hV??K?2Y!T4yi+!)qltZQ40^!ps0XM9>5^=99_Me*n;vnMcf0^LMs&WA z4>dIw)IRvPiC&_Ph^1C%p7sjk@v`W-)3c1gJ|f%(b_*^jZ;cZa$IMnOUZ=E9O;x(? zO49eDGF$oCGop5;TLc@0FK2h^lKcqop-Wh`21_=d)x+uIdhl(=Mgmq|zbq*jH7&Bc z2q(&i_bEO+HW}+D!Svy`X*l27Jk+ih7>Iv@FWIQRe!UgAT73>WuGBrcGvq}yAHS!I zl3w6|%*Cv+Ixq(x!ZPhS+K-m&+14o}iccqQ;;i+!k!14&H4`T#iDTv`@?+L@P2vFY zS2!2%z<5D%`Uu#Xb6T8rfP+f#RC-BJ z7ptFm5?0Q8u_zjf>r!=N)0j_;yE~Ja>Ke4bx66K2CflX0%GK@&qrrHIZr*LR*idUH zVhX*$C*gr~Fjx^iHfm~ojV!GFz||(TL%fJMWe5C&e5g6As6(Z8)bU2AVW!{>K0&4@r!Y&qMAe1t6VHFN=%!+x-LGr&TtV_;6zjB$nTEN7r!matMK!oz)ZkB5m9eTnX1sP_*r5*<@-k$tyPBR} z%zvj0Ik)25j8PoM#A7(dDi``9UUU^R%^r{9G7Rg`CgCN$;bg- zR#6d^F!=1Bf0W(H+29VgeJuAg`jbO^Q^BI!GRW?dQANWKy@*8Z=;co~^E00$Kf$!q z314AXp3hqL92pfod^Rn>w}15JeCS6^rV7EAE#`{uj9Jk0uioPBe3ZTREXvPzis*ml z-CVKUzsSi$ngOj>$Fo<1|ACuG0#B*hrRE?rTgz&(3-}36@fzoR*>l2cT+6#J<%%lX zD$cN(JO`dw%x_4TWUytByK`Wk<*!qbrML}?>u%OTt>fl*LCC&h!yo5<;slg!|F<)_ zbWMK|-Jr84qit9~l>+NT_uRML5;#y@3+xp7RV|bK*oFQuzh^bAw(ELS$$6aB>UlG8 zxXLlB5i8{a>PWdr*3Nz|)_pv(EK-3pMSiPGS40a;gSB-I2b&NpS0iUAimmG8;|HvvbqQ0hk+YHVt|XiH;Cl3B8-`yGR=lmvCiTlB@yNB6`Bs$2&?&HI6v9@~F zvF4;A+Oeo7gXXBA@(AwAig$BIJ&rsy4#j)qme7h!3;u$dtqMu&&5}2?<|bxYJ?w|r zVuuAx>9j8KPJfP=ph_+`fqk)$aF)F$s(d0-SCZbU!;(1mXXtK{++C;BaWleNp~RdKLpqAU%9I@*=Y#*Ak#*OeitO3*FcQL50GUMnOs^F2=? zLi<^VDh-AvbiczDJxi+onyevZSj)ec(E)WCOq=QmwicVq%2^V7U>h@eC1y@F173x6 zy0;r&K%Z!kz5&*XXV7sb2B?vh?ZcJvjk>X&>8OWIR;)_`vtuP87ITFWUD0akI}+W= zUu8ze9c=!I97k1g`RLUl1;>qoWU^9_flW zxNvbq-sY}WMRo_N7degio(S0W@%Xi|fOph({Th<6Gs&=Pm zgUogF;U4VsGX_zQ?LZNFZvE#q>4i)QYGPA(EZ5~3t!cX%$iCUVDoM{$!;sNml}H{0 z2B+(y7Pc3|%5UN(c%^coLxiskktou${NNBeVw4z8`oRa38Kc?uf5^}E0;_z>&YkIk3C9Aee?en> zYdgrHTz0QcW8AuTAx2nNhlaa}ApD|=jr;`1fP>JFS8nETW~38YMr${>yFu=v48Prq z1?;q-hWI;xIBUtt{<1nEHNX2gp6N)EJi?4?zuSlVsT$ZNADr)mQ}ewlxjy3 zYqX}~KJCyItCGlrlbJYTgzVIgOFMwYHlr)g*bYTD3^^Mge@U8+);vvDQf|&G@fc;C ztm9U&DrS@~v_keN>0g%>(Q8_bnIkdz9XqgYFxB;BgcuU5M+TU5>^fEfD)eq%u=)ZQ z`^R7LtI&EgJP1UdDYLSQnAx5=$2;+Ube|6>$4G{97pH05P1Gb!o>-KG8svP3UAp7qN9*@&{_<3>tpV1g?Snfgj7g}Vm94)f0t&pi&_4G%avb?K3V%?q2=4lUIp;6`vZ9=bP zCyJK;Cfn+jDlo5D%i_W5oSY7~V8>?H#np6K;udIt47Y4U_uAkcpf+p4qln`2IA{6l z+_qP{JO!<$d-RiMp*PTm_2aA9Cm-FaD(osg^S?M{ceTHnt&yDdv09=Y9aG+L5eqj~NnqQJNMd_@EP9G>Mj^xyEQ`ZwB_QR(uL&^C|rk;{Q7 zjSRvTX`Gg}lF!ce({a_zTJ;Y~hL6YudQkPGyE>k*%dK&_mAdIAz!B+Ssn3z4%S*Tl;lJ>!=&?*E= zcJM6eL%wB2WRMsVTFu%ptMVWx1;T{1%3obYOi{D25+n}I@uuus#S4;`x$8iopE6LV zD~Mn^*=2yvbJG1|KNq|W3m7+c)>9HxqdEgpCR4r=gGB?31>%H+VMJFJzi2GYgY#Iw z9klH^64hGS#JsfHIzB`bQ3Ea#&0u$4mVU@Jeu?+ISy=^$t{f$V(KCA?RGwUqll>#Q z$W9C+g__00p7&xsp)!?1{f73-c1Ig-9cpOZ3I8PH#T&uKVuz|E&O_as=Y%DDiUt0Z z#mOh@H?0<{D2we>O)P$MAFIR?v+VkPh?E&srX)I;@-_SSQP(--G}J-67fOL z2*X$^A7r0z5goAcRUP|PX1F>wG7HrDb@TahIrOMCnwfe5a0`kTc z^DGc!tH-PZlIRM+i6l`(qE0Tlk+!H&49PFIW?@B1%zi4_5@g3tc|v0$S9;Ve5*8~z zFT&votOu?WCU3TnJE2SBoj3zQi=pj1Y2K8}DF@rt?;WdyUvKWlNsxN!oP}HB+Y-(8!?<0q3>3Uk9`$% zV3zIY5s&Nf{f-BytgSgFz)l!k9zSdEt+QPrVZ9cjm>n~i2G`JWpnF?3Zv5>_T^T$9 zyr?>?lsj4LTS4)RY_%7FEsn$z0=@||XVfjm)3oJ&=gU)$m(S$d{Zg?jI-ToGJ zM%ZkXxQ+uOy&zO~p1wOF3Ej$8$kaf>YbPh2KrR`z>_FMduZ}YL;580em zWTeY7DfIxkA|$T2fw$AS*)#lD2@hX3hon^d#rp2|p#8FSyt)2=*n!7o-OWT{htc#V zENAB4N2kpX(y-=JnFU_`yjWpsE!UK`578dz^$ALGnVcAh-HN=_?=KSkT_<-a{m zxH0Stgy%#FdbT)dS5}t3nj-*ct2&us((vCU!TLWo_FR#z*lR z_JHswY!SP{o*^Xo&)#Jf3$>=#Szj3;q|^N^vQUVTmvkK~DzA`ZtFg783<`viX^@!W zEE_$jSQuK$21P8ED2IYaRXA9NSg$v({-tMW$R(Spxvz>LR9sfEbte8t&PgIhCkN;= zAez<41o?YNfIs75`D8K2se?Uv17^_0=-Ti!zooZ~g^4IVDb{Je_*kr1d9m8J8PO{~ zS+|yx!S95Navp>;!}Nz?_Shjg>0VO-bjF<%!#xp32e`jf&&^vDFkdSvi;zPZGkifB zWJz*PO!V3Kc`*2%=bixy0Ye?I`qKSArv2F8=L*HNNa9H z?96`|-!Hx2Qb>!_X^; zOH7s3>z#tr`9E0*7L(1(S|KL-Ko-!j+`0YDupe6$x6DQaAte@uTbB2U;W}V3c+Ea( zw0ZC+{0&T3_8W(3Mm%rX1i6hFxw^c)`3ZZ3e4NIi`sDoH_VkOk_Q)6q9APY^Lr-W~ z{TLocOrj6$r2d~B!QSd*^ja)x4Xb>gu{3{eZxsysJQBcb!ou=ncFAtUcbEXm@(c?d z1w0QfP1Y}W<=c3+B3-*F`}_?$q4v!(x^n?O=NmCQ;=8O3s$=!{hA}*eb@Yq}h`8g0 zUK@AiIC3*=y`EXvfK`@3QDuZxa3Hc7Qp0+&Z&3=4>+0Lfr$3wp+JDkL??w(M(Hq&e z6*o(|=p6r^A|^l7eNq-zWRweh!~n7~d5CUnYe;kL!PO1wjI{@0>mJ10>)(@g&`&++ z@)>bgEQ6SF4@F;c#qv)4O&JEKgt&egmGTF0Z+kb3g!xgGwUf~)9AM9XB~vnV55AQL z;p@wwvtiW=`@K~T@elF~pUqzXjd|-&xua#e%KEQ4SJtlPyB}Hqn6@3Ijv~NGxJT*fOV#=5Q`f3#W3!kuJlQC zS0>xqy*Mb#mLtgwvHI+mm%&Dg@^A(g_lNBEbbf|A8K+1oFY*DOKxsI(_Iin(vVV0Z z8ea~Pwz5oPb_e&sfAONm4%P8rkg?Z^rajZV(ieGjiHcO>1Rl$(@&|p&7kOgnGcbx+{XoAe_XBiPlME zC1g;}hmkwT$vqRyKG4=YXfafz>d^{;9MK3xNSVXONF$oTzfg+V`3ru99?G}md7?It zE=LgiaZ#?!dLT!3IG+3WH)O}dij`{bG!1O{ibq>BrHagAR5vOiG|<#Hrww}2SrUXYL;GV3S%x)Qdx&wuD1 z9bSijlh?0B8p=-ab#jHXO0G*TYcXDEYjg!Sd~ zdH__v>`dxOH9QlfB4?#*sPt%bv8Fq zOTNIjiVpGtsGY~)!{J_88ymz08Z+GH{3<(aRS3+_u4s7=&r`-kPZmaoZPf0}Q*JGS zVwu{nixC$!i#dw8?Ml*lhE>9+vQB3>utj)>enByCJ&WM^)Kz42#)Nahn3F3sd^P#pWJUFF()!idt<0^@!nl*4^swIu#BIWVP>+-K ziy=-)6yJ}=UOvl}{%+(Sa*oFr*@6A5kzePmq<_r+f68;Yon8-HdrFq4;yukXAAXx_ z{r2GBa}Q^o{wXVBx4j)C_Gvh;iiYuQ5I4kbC*Neo{%s_*l1)uCCrdaXb15FnbH+qj zIfI={dPBu*eZ!vbcQ@L6GxPXkwCTUIHa#W!VZ8kFAO&4h5cbK89ggx`dFP&9$U3RE zc|O`weoyzEC`k9p2=lJGaBmEEvM0$?hJTD!*b}E3$n(Qzkc~PCK4d!baOM=Bj+Yb> q)dfA*%4eP&K7pLYTv5hVN*|(R3@8+|_E4vp(r2hxe9@V}8 literal 0 HcmV?d00001 diff --git a/codec2/branches/0.7/raw/kristoff.raw b/codec2/branches/0.7/raw/kristoff.raw new file mode 100644 index 0000000000000000000000000000000000000000..9b0b465511bcd0a58d635af3c1fe24d54df96701 GIT binary patch literal 80000 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