You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
6.7 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 <janvi@veith.net>
  5. * Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation, either version 3 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <array>
  21. #include <vector>
  22. #include <string>
  23. /**
  24. * E-Values derived from a geometric sequence formula by Charles Renard were already
  25. * accepted and widely used before the ISO recommendation no. 3 has been published.
  26. * For this historical reason, rounding rules of some values are sometimes irregular.
  27. * Although all E-Values could be calculated at runtime, we initialize them in a lookup table
  28. * what seems the most easy way to consider any inconvenient irregular rules. Same table is
  29. * also used to lookup non calculable but readable BOM value strings. Supported E-series are:
  30. */
  31. // List of normalized values between 1 and 10
  32. // The terminal 0.0 value is a end of list value
  33. // Note also due to calculation time the E24 serie is the biggest usable.
  34. #define E24_VALUES 1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0,\
  35. 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1, 0.0
  36. #define E12_VALUES 1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 0.0
  37. #define E6_VALUES 1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 0.0
  38. #define E3_VALUES 1.0, 2.2, 4.7, 0.0
  39. #define E1_VALUES 1.0, 0.0
  40. // First value of resistor in ohm
  41. #define FIRST_VALUE 10
  42. // last value of resistor in ohm
  43. #define LAST_VALUE 1e6
  44. /**
  45. * List of handled E series values:
  46. * Note: series bigger than E24 have no interest because
  47. * - probably the user will fing the needed value inside these series
  48. * - the calculation time can be *very high* for series > E24
  49. */
  50. enum { E1, E3, E6, E12, E24 };
  51. /**
  52. * This calculator suggests solutions for 2R, 3R and 4R replacement combinations
  53. */
  54. enum { S2R, S3R, S4R };
  55. // R_DATA handles a resistor: string value, value and allowed to use
  56. struct R_DATA
  57. {
  58. R_DATA() :
  59. e_use( true ),
  60. e_value( 0.0 )
  61. {}
  62. R_DATA( const std::string& aName, double aValue )
  63. {
  64. e_use = true;
  65. e_name = aName;
  66. e_value = aValue;
  67. }
  68. bool e_use;
  69. std::string e_name;
  70. double e_value;
  71. };
  72. class E_SERIE
  73. {
  74. public:
  75. E_SERIE();
  76. /**
  77. * If any value of the selected E-serie not available, it can be entered as an exclude value.
  78. *
  79. * @param aValue is the value to exclude from calculation
  80. * Values to exclude are set to false in the selected E-serie source lookup table
  81. */
  82. void Exclude( double aValue );
  83. /**
  84. * initialize next calculation and erase results from previous calculation
  85. */
  86. void NewCalc();
  87. /**
  88. * called on calculate button to execute all the 2R, 3R and 4R calculations
  89. */
  90. void Calculate();
  91. /**
  92. * Interface for CheckBox, RadioButton, RequriedResistor and calculated Results
  93. */
  94. void SetSeries( uint32_t aSeries ) { m_series = aSeries; }
  95. void SetRequiredValue( double aValue ) { m_required_value = aValue; }
  96. // Accessor:
  97. const std::array<R_DATA,S4R+1>& GetResults() { return m_results; }
  98. private:
  99. /**
  100. * Build the list of R_DATA existing for a given serie
  101. * Series are E1, E6 ..
  102. * The values are extracted from the E96_VALUES list
  103. * @return the count of items added in list
  104. */
  105. int buildSerieData( int aEserie, double aList[] );
  106. /**
  107. * Build all 2R combinations from the selected E-serie values
  108. *
  109. * Pre-calculated value combinations are saved in intermediate look up table m_cmb_lut
  110. * @return is the number of found combinations what also depends from exclude values
  111. */
  112. uint32_t combine2();
  113. /**
  114. * Search for closest two component solution
  115. *
  116. * @param aSize is the number of valid 2R combinations in m_cmb_lut on where to search
  117. * The 2R result with smallest deviation will be saved in results
  118. */
  119. void simple_solution( uint32_t aSize );
  120. /**
  121. * Check if there is a better 3 R solution than previous one using only two components.
  122. *
  123. * @param aSize gives the number of available combinations to be checked inside m_cmb_lut
  124. * Therefore m_cmb_lut is combinated with the primary E-serie look up table
  125. * The 3R result with smallest deviation will be saved in results if better than 2R
  126. */
  127. void combine3( uint32_t aSize );
  128. /**
  129. * Check if there is a better four component solution.
  130. *
  131. * @param aSsize gives the number of 2R combinations to be checked inside m_cmb_lut
  132. * Occupied calculation time depends from number of available E-serie values
  133. * with the power of 4 why execution for E12 is conditional with 4R check box
  134. * for the case the previously found 3R solution is already exact
  135. */
  136. void combine4( uint32_t aSize );
  137. /*
  138. * Strip redundant braces from three component result
  139. *
  140. * Example: R1+(R2+R3) become R1+R2+R3
  141. * and R1|(R2|R3) become R1|R2|R3
  142. * while R1+(R2|R3) or (R1+R2)|R3) remains untouched
  143. */
  144. void strip3();
  145. /*
  146. * Strip redundant braces from four component result
  147. *
  148. * Example: (R1+R2)+(R3+R4) become R1+R2+R3+R4
  149. * and (R1|R2)|(R2|R3) become R1|R2|R3|R4
  150. * while (R1+R2)|(R3+R4) remains untouched
  151. */
  152. void strip4();
  153. private:
  154. std::vector<std::vector<R_DATA>> m_luts;
  155. /* Note: intermediate calculations use m_cmb_lut
  156. * if the biggest list is En, reserved array size should be 2*En*En of std::vector primary list.
  157. * 2 component combinations including redundant swappable terms are for the moment
  158. * ( using values between 10 ohms and 1Mohm )
  159. * 72 combinations for E1
  160. * 512 combinations for E3
  161. * 1922 combinations for E6
  162. * 7442 combinations for E12
  163. * 29282 combinations for E24
  164. */
  165. std::vector<R_DATA> m_cmb_lut; // intermediate 2R combinations
  166. std::array<R_DATA, S4R+1> m_results; // 2R, 3R and 4R results
  167. uint32_t m_series = E6; // Radio Button State
  168. uint32_t m_enable_4R = false; // Check Box 4R enable
  169. double m_required_value = 0.0; // required Resistor
  170. };