1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/*
* This program source code file
* is part of KiCad, a free EDA CAD application.
*
* Copyright The 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "eseries.h"
#include <array>
#include <optional>
#include <string>
#include <utility>
#include <vector>
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, const std::string& aName ) : value( aValue ), name( 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<std::optional<RESISTANCE>, 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<RESISTANCE> 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<RESISTANCE&, RESISTANCE&> findIn2RBuffer( double aTargetValue );
/**
* Calculate the best combination consisting of exactly 2, 3 or 4 resistors.
*/
RESISTANCE calculate2RSolution();
RESISTANCE calculate3RSolution();
RESISTANCE calculate4RSolution();
private:
std::vector<std::vector<RESISTANCE>> m_e_series;
std::vector<bool> m_exclude_mask;
std::vector<RESISTANCE> m_buffer_1R;
std::vector<RESISTANCE> m_buffer_2R;
uint32_t m_series = ESERIES::E6;
double m_target = 0;
std::array<std::optional<RESISTANCE>, NUMBER_OF_LEVELS> m_results;
};
|