/* * This program source code file * is part of KiCad, a free EDA CAD application. * * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. * * 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 . */ #pragma once #include "eseries.h" #include #include #include #include #include const double epsilon = 1e-12; // machine epsilon for floating-point equality testing // First value of resistor in Ohm // It should be first value of the decade, i.e. power of 10 // This value is only pertinent to the resistor calculator. // It is used to reduce the computational complexity of its calculations. // There are valid resistor values using E-series numbers below this // value and above the below LAST_VALUE. #define RES_EQUIV_CALC_FIRST_VALUE 10 // Last value of resistor in Ohm // This value is only pertinent to the resistor calculator. See above. #define RES_EQUIV_CALC_LAST_VALUE 1e6 // Struct representing resistance value together with its composition, e.g. {20.0, "10R + 10R"} struct RESISTANCE { double value; std::string name; RESISTANCE( double aValue = 0.0, std::string aName = "" ) : value( aValue ), name( std::move( aName ) ) { } }; class RES_EQUIV_CALC /*! \brief Performs calculations on E-series values primarily to find target values * as combinations (serial, parallel) of them. * * RES_EQUIV_CALC class stores and performs calcuations on E-series values. It currently * is targeted toward the resistor calculator and hard codes some limitations * to optimize its use in the resistor calculator. * * At this time these limitations are that this class handles only E-series up to * E24 and it does not consider resistor values below 10 Ohm or above 1M Ohm. */ { public: RES_EQUIV_CALC(); enum { S2R, S3R, S4R, NUMBER_OF_LEVELS }; /** * Set E-series to be used in calculations. * Correct values are from 0 to 4 inclusive, * representing series (consecutively) E1, E3, E6, E12, E24. * After changing the series, NewCalc must be called before running calculations. */ void SetSeries( uint32_t aSeries ); /** * Initialize next calculation, clear exclusion mask * and erase results from previous calculation. * * @param aTargetValue is the value (in Ohms) to be looked for */ void NewCalc( double aTargetValue ); /** * If any value of the selected E-series not available, it can be entered as an exclude value. * * @param aValue is the value (in Ohms) to exclude from calculation * Values to exclude are set to true in the current exclusion mask and will not be * considered during calculations. */ void Exclude( double aValue ); /** * Executes all the calculations. * Results are to be retrieved using GetResults (below). */ void Calculate(); /** * Accessor to calculation results. * Empty std::optional means that the exact value can be achieved using fewer resistors. */ const std::array, NUMBER_OF_LEVELS>& GetResults() { return m_results; } private: /** * Add values from aList to m_e_series tables. * Covers all decades between FIRST_VALUE and LAST_VALUE. */ std::vector buildSeriesData( const ESERIES::ESERIES_VALUES& aList ); /** * Build 1R buffer, which is selected E-series table with excluded values removed. */ void prepare1RBuffer(); /** * Build 2R buffer, which consists of all possible combinations of two resistors * from 1R buffer (serial and parallel), sorted by value. */ void prepare2RBuffer(); /** * Find in 2R buffer two values nearest to the given value (one smaller and one larger). * It always returns two valid values, even for input out of range or Nan. */ std::pair findIn2RBuffer( double aTargetValue ); /** * Calculate the best combination consisting of exactly 2, 3 or 4 resistors. */ RESISTANCE calculate2RSolution(); RESISTANCE calculate3RSolution(); RESISTANCE calculate4RSolution(); private: std::vector> m_e_series; std::vector m_exclude_mask; std::vector m_buffer_1R; std::vector m_buffer_2R; uint32_t m_series = ESERIES::E6; double m_target = 0; std::array, NUMBER_OF_LEVELS> m_results; };