1use itertools::Itertools;
29use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
30use serde::{Deserialize, Serialize};
31use std::fmt;
32use std::fs::File;
33use std::io::BufReader;
34use std::io::BufWriter;
35
36use crate::{utils, Bit, DecodingAlgo, Error, Interleaver};
37
38const CODE_POLYNOMIALS: [usize; 2] = [0o13, 0o15];
39const INVERSE_CODE_RATE: usize = 3;
40const NUM_TAIL_CODE_BITS: usize = 12;
41
42#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
44pub struct SimParams {
45 pub num_info_bits_per_block: u32,
47 pub decoding_algo: DecodingAlgo,
49 pub es_over_n0_db: f64,
51 pub num_block_errors_min: u32,
53 pub num_blocks_per_run: u32,
55 pub num_runs_min: u32,
57 pub num_runs_max: u32,
59}
60
61impl SimParams {
62 fn check(&self) -> Result<(), Error> {
64 if qpp_coefficients(self.num_info_bits_per_block as usize).is_err() {
65 return Err(Error::InvalidInput(format!(
66 "{} is not a valid number of information bits per block",
67 self.num_info_bits_per_block
68 )));
69 }
70 if self.num_blocks_per_run == 0 {
71 return Err(Error::InvalidInput(
72 "Number of blocks per run cannot be zero".to_string(),
73 ));
74 }
75 if self.num_runs_min > self.num_runs_max {
76 return Err(Error::InvalidInput(format!(
77 "Minimum number of runs ({}) exceeds maximum number of runs ({})",
78 self.num_runs_min, self.num_runs_max
79 )));
80 }
81 Ok(())
82 }
83
84 fn print(&self) {
86 eprintln!();
87 self.print_num_info_bits_per_block();
88 self.print_decoding_algo();
89 self.print_es_over_n0_db();
90 self.print_num_block_errors_min();
91 self.print_num_blocks_per_run();
92 self.print_num_runs_min();
93 self.print_num_runs_max();
94 }
95
96 fn print_num_info_bits_per_block(&self) {
98 eprintln!(
99 "{:?} information bits per block",
100 self.num_info_bits_per_block,
101 );
102 }
103
104 fn print_decoding_algo(&self) {
106 eprintln!("{}", self.decoding_algo);
107 }
108
109 fn print_es_over_n0_db(&self) {
111 eprintln!("Es/N0 of {} dB", self.es_over_n0_db);
112 }
113
114 fn print_num_block_errors_min(&self) {
116 eprintln!("Minimum of {} block errors", self.num_block_errors_min);
117 }
118
119 fn print_num_blocks_per_run(&self) {
121 eprintln!("{} blocks per run", self.num_blocks_per_run);
122 }
123
124 fn print_num_runs_min(&self) {
126 eprintln!("Minimum of {} runs", self.num_runs_min);
127 }
128
129 fn print_num_runs_max(&self) {
131 eprintln!("Maximum of {} runs", self.num_runs_max);
132 }
133}
134
135#[derive(Clone, PartialEq, Debug, Copy, Deserialize, Serialize)]
137pub struct SimResults {
138 pub params: SimParams,
140 pub num_blocks: u32,
142 pub num_info_bits: u32,
144 pub num_block_errors: u32,
146 pub num_info_bit_errors: u32,
148}
149
150impl SimResults {
151 #[must_use]
153 fn new(params: &SimParams) -> Self {
154 Self {
155 params: *params,
156 num_blocks: 0,
157 num_info_bits: 0,
158 num_block_errors: 0,
159 num_info_bit_errors: 0,
160 }
161 }
162
163 #[must_use]
165 pub fn block_error_rate(&self) -> f64 {
166 if self.num_blocks > 0 {
167 f64::from(self.num_block_errors) / f64::from(self.num_blocks)
168 } else {
169 0.0
170 }
171 }
172
173 #[must_use]
175 pub fn info_bit_error_rate(&self) -> f64 {
176 if self.num_info_bits > 0 {
177 f64::from(self.num_info_bit_errors) / f64::from(self.num_info_bits)
178 } else {
179 0.0
180 }
181 }
182
183 #[allow(dead_code)]
185 fn print_progress_message(&self) {
186 if self.run_complete() {
187 eprint!(
188 "\rBER = {}/{}, BLER = {}/{}",
189 self.num_info_bit_errors,
190 self.num_info_bits,
191 self.num_block_errors,
192 self.num_blocks,
193 );
194 if self.sim_complete() {
195 eprintln!();
196 }
197 }
198 }
199
200 fn run_complete(&self) -> bool {
202 self.num_blocks % self.params.num_blocks_per_run == 0
203 }
204
205 fn sim_complete(&self) -> bool {
207 self.run_complete()
208 && self.num_blocks >= self.params.num_runs_min * self.params.num_blocks_per_run
209 && (self.num_block_errors >= self.params.num_block_errors_min
210 || self.num_blocks >= self.params.num_runs_max * self.params.num_blocks_per_run)
211 }
212
213 fn update_after_block(&mut self, num_info_bit_errors_this_block: u32) {
215 self.num_blocks += 1;
216 self.num_info_bits += self.params.num_info_bits_per_block;
217 if num_info_bit_errors_this_block > 0 {
218 self.num_block_errors += 1;
219 self.num_info_bit_errors += num_info_bit_errors_this_block;
220 }
221 }
222}
223
224#[derive(Clone, Eq, Hash, PartialEq, Debug, Copy)]
226struct SimCase {
227 num_info_bits_per_block: u32,
228 decoding_algo: DecodingAlgo,
229}
230
231impl fmt::Display for SimCase {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(
234 f,
235 "{} bits/block, {}",
236 self.num_info_bits_per_block, self.decoding_algo
237 )
238 }
239}
240
241impl From<&SimResults> for SimCase {
242 fn from(results: &SimResults) -> SimCase {
243 SimCase {
244 num_info_bits_per_block: results.params.num_info_bits_per_block,
245 decoding_algo: results.params.decoding_algo,
246 }
247 }
248}
249
250pub fn encoder(info_bits: &[Bit]) -> Result<Vec<Bit>, Error> {
265 let qpp_interleaver = interleaver(info_bits.len())?;
266 crate::encoder(info_bits, &qpp_interleaver, &CODE_POLYNOMIALS)
267}
268
269pub fn decoder(code_bits_llr: &[f64], decoding_algo: DecodingAlgo) -> Result<Vec<Bit>, Error> {
287 if code_bits_llr.len() < NUM_TAIL_CODE_BITS {
288 return Err(Error::InvalidInput(format!(
289 "Expected a minimum of {NUM_TAIL_CODE_BITS} code bit LLR values (found {})",
290 code_bits_llr.len()
291 )));
292 }
293 let num_info_bits = (code_bits_llr.len() - NUM_TAIL_CODE_BITS) / INVERSE_CODE_RATE;
294 let qpp_interleaver = interleaver(num_info_bits)?;
295 crate::decoder(
296 code_bits_llr,
297 &qpp_interleaver,
298 &CODE_POLYNOMIALS,
299 decoding_algo,
300 )
301}
302
303#[allow(clippy::cast_possible_truncation)]
337#[allow(clippy::missing_panics_doc)]
338pub fn bpsk_awgn_sim(params: &SimParams) -> Result<SimResults, Error> {
339 params.check()?;
340 let mut results = SimResults::new(params);
341 while !results.sim_complete() {
342 let all_num_info_bit_errors_this_run: Vec<usize> = (0 .. params.num_blocks_per_run)
343 .into_par_iter()
344 .map(|_| {
345 let info_bits = utils::random_bits(params.num_info_bits_per_block as usize);
346 let code_bits = encoder(&info_bits).unwrap();
347 let code_bits_llr = utils::bpsk_awgn_channel(&code_bits, params.es_over_n0_db);
348 let info_bits_hat = decoder(&code_bits_llr, params.decoding_algo).unwrap();
349 utils::error_count(&info_bits_hat, &info_bits)
350 })
351 .collect();
352 for num_info_bit_errors_this_block in all_num_info_bit_errors_this_run {
355 results.update_after_block(num_info_bit_errors_this_block as u32);
356 }
357 }
358 Ok(results)
359}
360
361pub fn run_bpsk_awgn_sims(all_params: &[SimParams], json_filename: &str) -> Result<(), Error> {
395 for params in all_params {
396 if params.check().is_err() {
397 params.print();
398 eprintln!("WARNING: Ignoring above simulation parameters as they are invalid");
399 }
400 }
401 let all_results: Vec<SimResults> = all_params
402 .par_iter()
403 .filter_map(|params| bpsk_awgn_sim(params).ok())
404 .collect();
405 summarize_all_sim_results(&all_results);
406 save_all_sim_results_to_file(&all_results, json_filename)?;
407 Ok(())
408}
409
410pub fn summarize_all_sim_results_in_file(json_filename: &str) -> Result<(), Error> {
420 let all_results = all_sim_results_from_file(json_filename)?;
421 summarize_all_sim_results(&all_results);
422 Ok(())
423}
424
425fn save_all_sim_results_to_file(
427 all_results: &[SimResults],
428 json_filename: &str,
429) -> Result<(), Error> {
430 let writer = BufWriter::new(File::create(json_filename)?);
431 serde_json::to_writer_pretty(writer, all_results)?;
432 Ok(())
433}
434
435fn all_sim_results_from_file(json_filename: &str) -> Result<Vec<SimResults>, Error> {
437 let reader = BufReader::new(File::open(json_filename)?);
438 let all_results = serde_json::from_reader(reader)?;
439 Ok(all_results)
440}
441
442fn summarize_all_sim_results(all_results: &[SimResults]) {
444 let mut all_cases: Vec<SimCase> = all_results.iter().map(SimCase::from).unique().collect();
445 all_cases.sort_by_key(|case| case.num_info_bits_per_block);
446 for case in all_cases {
447 let all_results_for_case = all_sim_results_for_sim_case(all_results, case);
448 let all_es_over_n0_db = all_results_for_case
449 .iter()
450 .map(|&results| results.params.es_over_n0_db);
451 let all_info_bit_error_rate = all_results_for_case
452 .iter()
453 .map(|&results| results.info_bit_error_rate());
454 let all_block_error_rate = all_results_for_case
455 .iter()
456 .map(|&results| results.block_error_rate());
457 let banner_str = "=".repeat(case.to_string().len());
458 println!("\n{banner_str}");
459 println!("{case}");
460 println!("{banner_str}");
461 println!(" Es/N0 (dB) BER BLER");
462 all_info_bit_error_rate
463 .zip(all_block_error_rate)
464 .zip(all_es_over_n0_db)
465 .for_each(|((ber, bler), es_over_n0_db)| {
466 println!("{es_over_n0_db:>8.2} {ber:7.2e} {bler:7.2e}");
467 });
468 }
469}
470
471#[allow(clippy::cast_possible_truncation)]
473fn all_sim_results_for_sim_case(all_results: &[SimResults], case: SimCase) -> Vec<SimResults> {
474 let mut all_results_for_case = Vec::new();
475 for results in all_results {
476 if SimCase::from(results) == case {
477 all_results_for_case.push(*results);
478 }
479 }
480 all_results_for_case.sort_by_key(|results| (1e6 * results.params.es_over_n0_db) as i32);
481 all_results_for_case
482}
483
484fn interleaver(num_info_bits: usize) -> Result<Interleaver, Error> {
486 let (coeff1, coeff2) = qpp_coefficients(num_info_bits)?;
487 let perm: Vec<usize> = (0 .. num_info_bits)
488 .map(|out_index| ((coeff1 + coeff2 * out_index) * out_index) % num_info_bits)
489 .collect();
490 Interleaver::new(&perm)
491}
492
493fn qpp_coefficients(num_info_bits: usize) -> Result<(usize, usize), Error> {
495 if num_info_bits <= 128 {
496 qpp_coefficients_40_to_128_bits(num_info_bits)
497 } else if num_info_bits <= 256 {
498 qpp_coefficients_136_to_256_bits(num_info_bits)
499 } else if num_info_bits <= 512 {
500 qpp_coefficients_264_to_512_bits(num_info_bits)
501 } else if num_info_bits <= 1024 {
502 qpp_coefficients_528_to_1024_bits(num_info_bits)
503 } else if num_info_bits <= 2048 {
504 qpp_coefficients_1056_to_2048_bits(num_info_bits)
505 } else if num_info_bits <= 4096 {
506 qpp_coefficients_2112_to_4096_bits(num_info_bits)
507 } else {
508 qpp_coefficients_4160_to_6144_bits(num_info_bits)
509 }
510}
511
512fn qpp_coefficients_40_to_128_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
514 match num_info_bits {
515 40 => Ok((3, 10)),
516 48 => Ok((7, 12)),
517 56 => Ok((19, 42)),
518 64 => Ok((7, 16)),
519 72 => Ok((7, 18)),
520 80 => Ok((11, 20)),
521 88 => Ok((5, 22)),
522 96 => Ok((11, 24)),
523 104 => Ok((7, 26)),
524 112 => Ok((41, 84)),
525 120 => Ok((103, 90)),
526 128 => Ok((15, 32)),
527 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
528 num_info_bits,
529 ))),
530 }
531}
532
533fn qpp_coefficients_136_to_256_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
535 match num_info_bits {
536 136 => Ok((9, 34)),
537 144 => Ok((17, 108)),
538 152 => Ok((9, 38)),
539 160 => Ok((21, 120)),
540 168 => Ok((101, 84)),
541 176 => Ok((21, 44)),
542 184 => Ok((57, 46)),
543 192 => Ok((23, 48)),
544 200 => Ok((13, 50)),
545 208 => Ok((27, 52)),
546 216 => Ok((11, 36)),
547 224 => Ok((27, 56)),
548 232 => Ok((85, 58)),
549 240 => Ok((29, 60)),
550 248 => Ok((33, 62)),
551 256 => Ok((15, 32)),
552 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
553 num_info_bits,
554 ))),
555 }
556}
557
558fn qpp_coefficients_264_to_512_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
560 match num_info_bits {
561 264 => Ok((17, 198)),
562 272 => Ok((33, 68)),
563 280 => Ok((103, 210)),
564 288 => Ok((19, 36)),
565 296 => Ok((19, 74)),
566 304 => Ok((37, 76)),
567 312 => Ok((19, 78)),
568 320 => Ok((21, 120)),
569 328 => Ok((21, 82)),
570 336 => Ok((115, 84)),
571 344 => Ok((193, 86)),
572 352 => Ok((21, 44)),
573 360 => Ok((133, 90)),
574 368 => Ok((81, 46)),
575 376 => Ok((45, 94)),
576 384 => Ok((23, 48)),
577 392 => Ok((243, 98)),
578 400 => Ok((151, 40)),
579 408 => Ok((155, 102)),
580 416 => Ok((25, 52)),
581 424 => Ok((51, 106)),
582 432 => Ok((47, 72)),
583 440 => Ok((91, 110)),
584 448 => Ok((29, 168)),
585 456 => Ok((29, 114)),
586 464 => Ok((247, 58)),
587 472 => Ok((29, 118)),
588 480 => Ok((89, 180)),
589 488 => Ok((91, 122)),
590 496 => Ok((157, 62)),
591 504 => Ok((55, 84)),
592 512 => Ok((31, 64)),
593 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
594 num_info_bits,
595 ))),
596 }
597}
598
599fn qpp_coefficients_528_to_1024_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
601 match num_info_bits {
602 528 => Ok((17, 66)),
603 544 => Ok((35, 68)),
604 560 => Ok((227, 420)),
605 576 => Ok((65, 96)),
606 592 => Ok((19, 74)),
607 608 => Ok((37, 76)),
608 624 => Ok((41, 234)),
609 640 => Ok((39, 80)),
610 656 => Ok((185, 82)),
611 672 => Ok((43, 252)),
612 688 => Ok((21, 86)),
613 704 => Ok((155, 44)),
614 720 => Ok((79, 120)),
615 736 => Ok((139, 92)),
616 752 => Ok((23, 94)),
617 768 => Ok((217, 48)),
618 784 => Ok((25, 98)),
619 800 => Ok((17, 80)),
620 816 => Ok((127, 102)),
621 832 => Ok((25, 52)),
622 848 => Ok((239, 106)),
623 864 => Ok((17, 48)),
624 880 => Ok((137, 110)),
625 896 => Ok((215, 112)),
626 912 => Ok((29, 114)),
627 928 => Ok((15, 58)),
628 944 => Ok((147, 118)),
629 960 => Ok((29, 60)),
630 976 => Ok((59, 122)),
631 992 => Ok((65, 124)),
632 1008 => Ok((55, 84)),
633 1024 => Ok((31, 64)),
634 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
635 num_info_bits,
636 ))),
637 }
638}
639
640fn qpp_coefficients_1056_to_2048_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
642 match num_info_bits {
643 1056 => Ok((17, 66)),
644 1088 => Ok((171, 204)),
645 1120 => Ok((67, 140)),
646 1152 => Ok((35, 72)),
647 1184 => Ok((19, 74)),
648 1216 => Ok((39, 76)),
649 1248 => Ok((19, 78)),
650 1280 => Ok((199, 240)),
651 1312 => Ok((21, 82)),
652 1344 => Ok((211, 252)),
653 1376 => Ok((21, 86)),
654 1408 => Ok((43, 88)),
655 1440 => Ok((149, 60)),
656 1472 => Ok((45, 92)),
657 1504 => Ok((49, 846)),
658 1536 => Ok((71, 48)),
659 1568 => Ok((13, 28)),
660 1600 => Ok((17, 80)),
661 1632 => Ok((25, 102)),
662 1664 => Ok((183, 104)),
663 1696 => Ok((55, 954)),
664 1728 => Ok((127, 96)),
665 1760 => Ok((27, 110)),
666 1792 => Ok((29, 112)),
667 1824 => Ok((29, 114)),
668 1856 => Ok((57, 116)),
669 1888 => Ok((45, 354)),
670 1920 => Ok((31, 120)),
671 1952 => Ok((59, 610)),
672 1984 => Ok((185, 124)),
673 2016 => Ok((113, 420)),
674 2048 => Ok((31, 64)),
675 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
676 num_info_bits,
677 ))),
678 }
679}
680
681fn qpp_coefficients_2112_to_4096_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
683 match num_info_bits {
684 2112 => Ok((17, 66)),
685 2176 => Ok((171, 136)),
686 2240 => Ok((209, 420)),
687 2304 => Ok((253, 216)),
688 2368 => Ok((367, 444)),
689 2432 => Ok((265, 456)),
690 2496 => Ok((181, 468)),
691 2560 => Ok((39, 80)),
692 2624 => Ok((27, 164)),
693 2688 => Ok((127, 504)),
694 2752 => Ok((143, 172)),
695 2816 => Ok((43, 88)),
696 2880 => Ok((29, 300)),
697 2944 => Ok((45, 92)),
698 3008 => Ok((157, 188)),
699 3072 => Ok((47, 96)),
700 3136 => Ok((13, 28)),
701 3200 => Ok((111, 240)),
702 3264 => Ok((443, 204)),
703 3328 => Ok((51, 104)),
704 3392 => Ok((51, 212)),
705 3456 => Ok((451, 192)),
706 3520 => Ok((257, 220)),
707 3584 => Ok((57, 336)),
708 3648 => Ok((313, 228)),
709 3712 => Ok((271, 232)),
710 3776 => Ok((179, 236)),
711 3840 => Ok((331, 120)),
712 3904 => Ok((363, 244)),
713 3968 => Ok((375, 248)),
714 4032 => Ok((127, 168)),
715 4096 => Ok((31, 64)),
716 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
717 num_info_bits,
718 ))),
719 }
720}
721
722fn qpp_coefficients_4160_to_6144_bits(num_info_bits: usize) -> Result<(usize, usize), Error> {
724 match num_info_bits {
725 4160 => Ok((33, 130)),
726 4224 => Ok((43, 264)),
727 4288 => Ok((33, 134)),
728 4352 => Ok((477, 408)),
729 4416 => Ok((35, 138)),
730 4480 => Ok((233, 280)),
731 4544 => Ok((357, 142)),
732 4608 => Ok((337, 480)),
733 4672 => Ok((37, 146)),
734 4736 => Ok((71, 444)),
735 4800 => Ok((71, 120)),
736 4864 => Ok((37, 152)),
737 4928 => Ok((39, 462)),
738 4992 => Ok((127, 234)),
739 5056 => Ok((39, 158)),
740 5120 => Ok((39, 80)),
741 5184 => Ok((31, 96)),
742 5248 => Ok((113, 902)),
743 5312 => Ok((41, 166)),
744 5376 => Ok((251, 336)),
745 5440 => Ok((43, 170)),
746 5504 => Ok((21, 86)),
747 5568 => Ok((43, 174)),
748 5632 => Ok((45, 176)),
749 5696 => Ok((45, 178)),
750 5760 => Ok((161, 120)),
751 5824 => Ok((89, 182)),
752 5888 => Ok((323, 184)),
753 5952 => Ok((47, 186)),
754 6016 => Ok((23, 94)),
755 6080 => Ok((47, 190)),
756 6144 => Ok((263, 480)),
757 _ => Err(Error::InvalidInput(invalid_num_info_bits_message(
758 num_info_bits,
759 ))),
760 }
761}
762
763fn invalid_num_info_bits_message(num_info_bits: usize) -> String {
765 format!("Number of information bits {num_info_bits} is not in Table 5.1.3-3 of 3GPP TS 36.212")
766}
767
768#[cfg(test)]
769mod tests_of_simparams {
770 use super::*;
771
772 #[test]
773 fn test_check() {
774 let params = SimParams {
776 num_info_bits_per_block: 32,
777 decoding_algo: DecodingAlgo::LinearLogMAP(8),
778 es_over_n0_db: -3.0,
779 num_block_errors_min: 10,
780 num_blocks_per_run: 1,
781 num_runs_min: 1,
782 num_runs_max: 2,
783 };
784 assert!(params.check().is_err());
785 let params = SimParams {
786 num_info_bits_per_block: 40,
787 decoding_algo: DecodingAlgo::LinearLogMAP(8),
788 es_over_n0_db: -3.0,
789 num_block_errors_min: 10,
790 num_blocks_per_run: 0,
791 num_runs_min: 1,
792 num_runs_max: 2,
793 };
794 assert!(params.check().is_err());
795 let params = SimParams {
796 num_info_bits_per_block: 40,
797 decoding_algo: DecodingAlgo::LinearLogMAP(8),
798 es_over_n0_db: -3.0,
799 num_block_errors_min: 10,
800 num_blocks_per_run: 1,
801 num_runs_min: 2,
802 num_runs_max: 1,
803 };
804 assert!(params.check().is_err());
805 let params = SimParams {
807 num_info_bits_per_block: 40,
808 decoding_algo: DecodingAlgo::LinearLogMAP(8),
809 es_over_n0_db: -3.0,
810 num_block_errors_min: 10,
811 num_blocks_per_run: 1,
812 num_runs_min: 1,
813 num_runs_max: 2,
814 };
815 assert!(params.check().is_ok());
816 }
817
818 #[test]
819 fn test_print() {
820 let params = SimParams {
821 num_info_bits_per_block: 40,
822 decoding_algo: DecodingAlgo::LinearLogMAP(8),
823 es_over_n0_db: -3.0,
824 num_block_errors_min: 100,
825 num_blocks_per_run: 1000,
826 num_runs_min: 1,
827 num_runs_max: 10,
828 };
829 params.print();
830 }
831}
832
833#[cfg(test)]
834mod tests_of_simresults {
835 use super::*;
836 use float_eq::assert_float_eq;
837
838 fn params_for_test() -> SimParams {
839 SimParams {
840 num_info_bits_per_block: 48,
841 decoding_algo: DecodingAlgo::LinearLogMAP(8),
842 es_over_n0_db: -3.0,
843 num_block_errors_min: 100,
844 num_blocks_per_run: 1000,
845 num_runs_min: 1,
846 num_runs_max: 10,
847 }
848 }
849
850 fn results_for_test(num_blocks: u32, num_block_errors: u32) -> SimResults {
851 let params = params_for_test();
852 let num_info_bits = num_blocks * params.num_info_bits_per_block;
853 let num_info_bit_errors = num_block_errors * 10;
854 SimResults {
855 params,
856 num_blocks,
857 num_info_bits,
858 num_block_errors,
859 num_info_bit_errors,
860 }
861 }
862
863 #[test]
864 fn test_new() {
865 let results = SimResults::new(¶ms_for_test());
866 assert_eq!(results.num_blocks, 0);
867 assert_eq!(results.num_info_bits, 0);
868 assert_eq!(results.num_block_errors, 0);
869 assert_eq!(results.num_info_bit_errors, 0);
870 }
871
872 #[test]
873 fn test_block_error_rate() {
874 let results = results_for_test(2000, 10);
875 assert_float_eq!(results.block_error_rate(), 10.0 / 2000.0, abs <= 1e-8);
876 }
877
878 #[test]
879 fn test_info_bit_error_rate() {
880 let results = results_for_test(2000, 10);
881 assert_float_eq!(results.info_bit_error_rate(), 100.0 / 96000.0, abs <= 1e-8);
882 }
883
884 #[test]
885 fn test_print_progress_message() {
886 let results = results_for_test(1000, 10);
887 results.print_progress_message();
888 }
889
890 #[test]
891 fn test_run_complete() {
892 let results = results_for_test(999, 0);
893 assert!(!results.run_complete());
894 let results = results_for_test(1000, 0);
895 assert!(results.run_complete());
896 let results = results_for_test(1001, 0);
897 assert!(!results.run_complete());
898 }
899
900 #[test]
901 fn test_sim_complete() {
902 let results = results_for_test(5000, 99);
904 assert!(!results.sim_complete());
905 let results = results_for_test(5000, 100);
906 assert!(results.sim_complete());
907 let results = results_for_test(4999, 500);
909 assert!(!results.sim_complete());
910 let results = results_for_test(5000, 500);
911 assert!(results.sim_complete());
912 let results = results_for_test(5001, 500);
913 assert!(!results.sim_complete());
914 let results = results_for_test(999, 500);
916 assert!(!results.sim_complete());
917 let results = results_for_test(1000, 500);
918 assert!(results.sim_complete());
919 let results = results_for_test(9999, 50);
921 assert!(!results.sim_complete());
922 let results = results_for_test(10000, 50);
923 assert!(results.sim_complete());
924 }
925
926 #[test]
927 fn test_update_after_block() {
928 let mut results = results_for_test(100, 10);
930 results.update_after_block(0);
931 assert_eq!(results.num_blocks, 101);
932 assert_eq!(results.num_info_bits, 4848);
933 assert_eq!(results.num_block_errors, 10);
934 assert_eq!(results.num_info_bit_errors, 100);
935 let mut results = results_for_test(100, 10);
937 results.update_after_block(10);
938 assert_eq!(results.num_blocks, 101);
939 assert_eq!(results.num_info_bits, 4848);
940 assert_eq!(results.num_block_errors, 11);
941 assert_eq!(results.num_info_bit_errors, 110);
942 }
943}
944
945#[cfg(test)]
946mod tests_of_functions {
947 use super::*;
948
949 #[test]
950 fn test_encoder() {
951 let info_bits = utils::random_bits(40);
952 assert!(encoder(&info_bits).is_ok());
953 }
954
955 #[test]
956 fn test_decoder() {
957 let code_bits_llr = utils::bpsk_awgn_channel(&utils::random_bits(132), 10.0);
958 assert!(decoder(&code_bits_llr, DecodingAlgo::LinearLogMAP(8)).is_ok());
959 }
960
961 #[test]
962 fn test_bpsk_awgn_sim() {
963 let params = SimParams {
965 num_info_bits_per_block: 32,
966 decoding_algo: DecodingAlgo::LinearLogMAP(8),
967 es_over_n0_db: -3.0,
968 num_block_errors_min: 10,
969 num_blocks_per_run: 10,
970 num_runs_min: 1,
971 num_runs_max: 2,
972 };
973 assert!(bpsk_awgn_sim(¶ms).is_err());
974 let params = SimParams {
976 num_info_bits_per_block: 40,
977 decoding_algo: DecodingAlgo::LinearLogMAP(8),
978 es_over_n0_db: -3.0,
979 num_block_errors_min: 10,
980 num_blocks_per_run: 10,
981 num_runs_min: 1,
982 num_runs_max: 2,
983 };
984 assert!(bpsk_awgn_sim(¶ms).is_ok());
985 }
986
987 #[test]
988 fn test_run_bpsk_awgn_sims() {
989 let all_params = vec![
990 SimParams {
991 num_info_bits_per_block: 36,
992 decoding_algo: DecodingAlgo::LinearLogMAP(8),
993 es_over_n0_db: -3.0,
994 num_block_errors_min: 20,
995 num_blocks_per_run: 10,
996 num_runs_min: 1,
997 num_runs_max: 2,
998 },
999 SimParams {
1000 num_info_bits_per_block: 40,
1001 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1002 es_over_n0_db: -3.0,
1003 num_block_errors_min: 10,
1004 num_blocks_per_run: 10,
1005 num_runs_min: 1,
1006 num_runs_max: 2,
1007 },
1008 SimParams {
1009 num_info_bits_per_block: 44,
1010 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1011 es_over_n0_db: -3.0,
1012 num_block_errors_min: 10,
1013 num_blocks_per_run: 10,
1014 num_runs_min: 1,
1015 num_runs_max: 2,
1016 },
1017 SimParams {
1018 num_info_bits_per_block: 48,
1019 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1020 es_over_n0_db: -3.0,
1021 num_block_errors_min: 10,
1022 num_blocks_per_run: 10,
1023 num_runs_min: 1,
1024 num_runs_max: 2,
1025 },
1026 ];
1027 run_bpsk_awgn_sims(&all_params, "results.json").unwrap();
1028 }
1029
1030 fn all_sim_params_for_test() -> Vec<SimParams> {
1031 let mut all_params = Vec::new();
1032 for num_info_bits_per_block in [40, 48] {
1033 for es_over_n0_db in [-3.5, -3.0, -4.0] {
1034 all_params.push(SimParams {
1035 num_info_bits_per_block,
1036 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1037 es_over_n0_db,
1038 num_block_errors_min: 20,
1039 num_blocks_per_run: 10,
1040 num_runs_min: 1,
1041 num_runs_max: 10,
1042 });
1043 }
1044 }
1045 all_params
1046 }
1047
1048 fn all_sim_results_for_test(all_params: &[SimParams]) -> Vec<SimResults> {
1049 let mut all_results = Vec::new();
1050 for params in all_params {
1051 all_results.push(SimResults::new(params));
1052 }
1053 all_results
1054 }
1055
1056 #[test]
1057 fn test_summarize_all_sim_results() {
1058 let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1059 summarize_all_sim_results(&all_results);
1060 }
1061
1062 #[test]
1063 fn test_all_sim_results_for_sim_case() {
1064 let all_results = all_sim_results_for_test(&all_sim_params_for_test());
1065 assert_eq!(
1066 all_sim_results_for_sim_case(
1067 &all_results,
1068 SimCase {
1069 num_info_bits_per_block: 40,
1070 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1071 },
1072 ),
1073 [all_results[2], all_results[0], all_results[1]]
1074 );
1075 assert_eq!(
1076 all_sim_results_for_sim_case(
1077 &all_results,
1078 SimCase {
1079 num_info_bits_per_block: 48,
1080 decoding_algo: DecodingAlgo::LinearLogMAP(8),
1081 },
1082 ),
1083 [all_results[5], all_results[3], all_results[4]]
1084 );
1085 }
1086
1087 #[test]
1088 fn test_interleaver() {
1089 assert!(interleaver(32).is_err());
1091 for num in 0 .. 60 {
1093 let num_info_bits = 40 + 8 * num;
1094 assert!(interleaver(num_info_bits).is_ok());
1095 }
1096 for num in 0 .. 32 {
1097 let num_info_bits = 528 + 16 * num;
1098 assert!(interleaver(num_info_bits).is_ok());
1099 }
1100 for num in 0 .. 32 {
1101 let num_info_bits = 1056 + 32 * num;
1102 assert!(interleaver(num_info_bits).is_ok());
1103 }
1104 for num in 0 .. 64 {
1105 let num_info_bits = 2112 + 64 * num;
1106 assert!(interleaver(num_info_bits).is_ok());
1107 }
1108 assert!(interleaver(6208).is_err());
1110 }
1111
1112 #[test]
1113 fn test_qpp_coefficients() {
1114 assert!(qpp_coefficients(32).is_err());
1116 for num in 0 .. 60 {
1118 let num_info_bits = 40 + 8 * num;
1119 assert!(qpp_coefficients(num_info_bits).is_ok());
1120 }
1121 for num in 0 .. 32 {
1122 let num_info_bits = 528 + 16 * num;
1123 assert!(qpp_coefficients(num_info_bits).is_ok());
1124 }
1125 for num in 0 .. 32 {
1126 let num_info_bits = 1056 + 32 * num;
1127 assert!(qpp_coefficients(num_info_bits).is_ok());
1128 }
1129 for num in 0 .. 64 {
1130 let num_info_bits = 2112 + 64 * num;
1131 assert!(qpp_coefficients(num_info_bits).is_ok());
1132 }
1133 assert!(qpp_coefficients(6208).is_err());
1135 }
1136
1137 #[test]
1138 fn test_qpp_coefficients_40_to_128_bits() {
1139 assert!(qpp_coefficients_40_to_128_bits(32).is_err());
1141 assert!(qpp_coefficients_40_to_128_bits(84).is_err());
1142 assert!(qpp_coefficients_40_to_128_bits(136).is_err());
1143 assert_eq!(qpp_coefficients_40_to_128_bits(40).unwrap(), (3, 10));
1145 assert_eq!(qpp_coefficients_40_to_128_bits(128).unwrap(), (15, 32));
1146 }
1147
1148 #[test]
1149 fn test_qpp_coefficients_136_to_256_bits() {
1150 assert!(qpp_coefficients_136_to_256_bits(128).is_err());
1152 assert!(qpp_coefficients_136_to_256_bits(196).is_err());
1153 assert!(qpp_coefficients_136_to_256_bits(264).is_err());
1154 assert_eq!(qpp_coefficients_136_to_256_bits(136).unwrap(), (9, 34));
1156 assert_eq!(qpp_coefficients_136_to_256_bits(256).unwrap(), (15, 32));
1157 }
1158
1159 #[test]
1160 fn test_qpp_coefficients_264_to_512_bits() {
1161 assert!(qpp_coefficients_264_to_512_bits(256).is_err());
1163 assert!(qpp_coefficients_264_to_512_bits(388).is_err());
1164 assert!(qpp_coefficients_264_to_512_bits(520).is_err());
1165 assert_eq!(qpp_coefficients_264_to_512_bits(264).unwrap(), (17, 198));
1167 assert_eq!(qpp_coefficients_264_to_512_bits(512).unwrap(), (31, 64));
1168 }
1169
1170 #[test]
1171 fn test_qpp_coefficients_528_to_1024_bits() {
1172 assert!(qpp_coefficients_528_to_1024_bits(512).is_err());
1174 assert!(qpp_coefficients_528_to_1024_bits(776).is_err());
1175 assert!(qpp_coefficients_528_to_1024_bits(1040).is_err());
1176 assert_eq!(qpp_coefficients_528_to_1024_bits(528).unwrap(), (17, 66));
1178 assert_eq!(qpp_coefficients_528_to_1024_bits(1024).unwrap(), (31, 64));
1179 }
1180
1181 #[test]
1182 fn test_qpp_coefficients_1056_to_2048_bits() {
1183 assert!(qpp_coefficients_1056_to_2048_bits(1024).is_err());
1185 assert!(qpp_coefficients_1056_to_2048_bits(1552).is_err());
1186 assert!(qpp_coefficients_1056_to_2048_bits(2080).is_err());
1187 assert_eq!(qpp_coefficients_1056_to_2048_bits(1056).unwrap(), (17, 66));
1189 assert_eq!(qpp_coefficients_1056_to_2048_bits(2048).unwrap(), (31, 64));
1190 }
1191
1192 #[test]
1193 fn test_qpp_coefficients_2112_to_4096_bits() {
1194 assert!(qpp_coefficients_2112_to_4096_bits(2048).is_err());
1196 assert!(qpp_coefficients_2112_to_4096_bits(3104).is_err());
1197 assert!(qpp_coefficients_2112_to_4096_bits(4160).is_err());
1198 assert_eq!(qpp_coefficients_2112_to_4096_bits(2112).unwrap(), (17, 66));
1200 assert_eq!(qpp_coefficients_2112_to_4096_bits(4096).unwrap(), (31, 64));
1201 }
1202
1203 #[test]
1204 fn test_qpp_coefficients_4160_to_6144_bits() {
1205 assert!(qpp_coefficients_4160_to_6144_bits(4096).is_err());
1207 assert!(qpp_coefficients_4160_to_6144_bits(5152).is_err());
1208 assert!(qpp_coefficients_4160_to_6144_bits(6208).is_err());
1209 assert_eq!(qpp_coefficients_4160_to_6144_bits(4160).unwrap(), (33, 130));
1211 assert_eq!(
1212 qpp_coefficients_4160_to_6144_bits(6144).unwrap(),
1213 (263, 480)
1214 );
1215 }
1216}