File: resistor_substitution_utils.h

package info (click to toggle)
kicad 9.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 770,320 kB
  • sloc: cpp: 961,692; ansic: 121,001; xml: 66,428; python: 18,387; sh: 1,010; awk: 301; asm: 292; makefile: 227; javascript: 167; perl: 10
file content (158 lines) | stat: -rw-r--r-- 5,168 bytes parent folder | download | duplicates (3)
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;
};