[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <a9c8457f-a364-46e2-9e31-ceab0e1c9894@baylibre.com>
Date: Wed, 13 Aug 2025 17:52:04 -0500
From: David Lechner <dlechner@...libre.com>
To: Ben Collins <bcollins@...ter.com>, Jonathan Cameron <jic23@...nel.org>,
Nuno Sรก <nuno.sa@...log.com>,
Andy Shevchenko <andy@...nel.org>
Cc: linux-iio@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2 5/5] iio: mcp9600: Add support for IIR filter
On 8/13/25 10:15 AM, Ben Collins wrote:
> MCP9600 supports an IIR filter with 7 levels. Add IIR attribute
> to allow get/set of this value.
>
> Signed-off-by: Ben Collins <bcollins@...ter.com>
> ---
> drivers/iio/temperature/mcp9600.c | 43 +++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
>
> diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
> index 5ead565f1bd8c..5bed3a35ae65e 100644
> --- a/drivers/iio/temperature/mcp9600.c
> +++ b/drivers/iio/temperature/mcp9600.c
> @@ -31,6 +31,7 @@
> #define MCP9600_STATUS_ALERT(x) BIT(x)
> #define MCP9600_SENSOR_CFG 0x5
> #define MCP9600_SENSOR_TYPE_MASK GENMASK(6, 4)
> +#define MCP9600_FILTER_MASK GENMASK(2, 0)
> #define MCP9600_ALERT_CFG1 0x8
> #define MCP9600_ALERT_CFG(x) (MCP9600_ALERT_CFG1 + (x - 1))
> #define MCP9600_ALERT_CFG_ENABLE BIT(0)
> @@ -111,6 +112,7 @@ static const struct iio_event_spec mcp9600_events[] = {
> .address = MCP9600_HOT_JUNCTION, \
> .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
> BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE), \
> .event_spec = &mcp9600_events[hj_ev_spec_off], \
> .num_event_specs = hj_num_ev, \
> @@ -149,6 +151,7 @@ static const struct iio_chan_spec mcp9600_channels[][2] = {
> struct mcp9600_data {
> struct i2c_client *client;
> u32 thermocouple_type;
> + u32 filter_level;
> };
>
> static int mcp9600_read(struct mcp9600_data *data,
> @@ -186,6 +189,9 @@ static int mcp9600_read_raw(struct iio_dev *indio_dev,
> case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
> *val = mcp9600_tc_types[data->thermocouple_type];
> return IIO_VAL_CHAR;
> + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> + *val = data->filter_level;
We can't just pass the raw value through for this. The ABI is defined
in Documentation/ABI/testing/sysfs-bus-iio and states that the value
is the frequency in Hz.
So we need to do the math to convert from the register value to
the required value.
I'm a bit rusty on my discrete time math, so I had chatgpt help me
do the transform of the function from the datasheet to a transfer
function and use that to find the frequency response.
It seemed to match what my textbook was telling me, so hopefully
it got it right.
Then it spit out the following program that can be used to make
a table of 3dB points for a given sampling frequency. If I read the
datasheet right, the sampling frequency depends on the number of
bits being read.
For example, for 3 Hz sample rate (18-bit samples), I got:
n f_3dB (Hz)
1 0.58774
2 0.24939
3 0.12063
4 0.05984
5 0.02986
6 0.01492
7 0.00746
I had to skip n=0 though since that is undefined. Not sure how we
handle that since it means no filter. Maybe Jonathan can advise?
```python
import numpy as np
import pandas as pd
# Sampling rate (can be replaced with actual sampling rate if known)
fs = 1.0 # Hz
# Define alpha as a function of n
def alpha(n):
return 2 / (2**n + 1)
# Compute 3 dB frequency for each n from 0 to 7
results = []
for n in range(0, 8):
a = alpha(n)
numerator = -(a**2 + 2*a - 2)
denominator = 2 * (1 - a)
cos_val = numerator / denominator
if -1 <= cos_val <= 1:
omega_3dB = np.arccos(cos_val) # radians/sample
f_3dB = (omega_3dB * fs) / (2 * np.pi) # Hz
else:
f_3dB = np.nan # Outside arccos domain
results.append({
"n": n,
"alpha": round(a, 5),
"f_3dB (Hz)": None if np.isnan(f_3dB) else round(f_3dB, 5)
})
# Display the results
df = pd.DataFrame(results)
print(df)
```
Here is the chatgpt transcript for checking the math:
To find the **3 dB point** (i.e., the cutoff frequency) of the given digital low-pass filter, we need to analyze its frequency response. The equation you've provided is a common **first-order IIR low-pass filter**:
$$
Y_k = (1 - n) \cdot Y_{k-1} + n \cdot X_k
$$
Where:
* $Y_k$: current filtered output
* $Y_{k-1}$: previous filtered output
* $X_k$: current input (unfiltered)
* $n$: filter coefficient (0 < $n$ < 1)
---
### Step 1: Transfer Function
We can find the transfer function $H(z)$ using Z-transforms.
Take the Z-transform of both sides:
$$
Y(z) = (1 - n) \cdot z^{-1} Y(z) + n \cdot X(z)
$$
Solve for $H(z) = \frac{Y(z)}{X(z)}$:
$$
Y(z) \left(1 - (1 - n) z^{-1} \right) = n X(z)
$$
$$
H(z) = \frac{Y(z)}{X(z)} = \frac{n}{1 - (1 - n) z^{-1}}
$$
---
### Step 2: Frequency Response
Substitute $z = e^{j\omega}$ to find the frequency response:
$$
H(e^{j\omega}) = \frac{n}{1 - (1 - n) e^{-j\omega}}
$$
We want the magnitude response $|H(e^{j\omega})|$, and the **3 dB point** is defined where the magnitude drops to:
$$
|H(e^{j\omega_{3dB}})| = \frac{1}{\sqrt{2}} \cdot |H(e^{j0})|
$$
At $\omega = 0$:
$$
|H(e^{j0})| = \frac{n}{1 - (1 - n)} = 1
$$
So the 3 dB point occurs when:
$$
|H(e^{j\omega_{3dB}})| = \frac{1}{\sqrt{2}} \approx 0.707
$$
---
### Step 3: Solving Numerically (Approximation)
The magnitude of the frequency response is:
$$
|H(e^{j\omega})| = \frac{n}{\sqrt{1 - 2(1 - n)\cos(\omega) + (1 - n)^2}}
$$
Set this equal to 0.707:
$$
\frac{n}{\sqrt{1 - 2(1 - n)\cos(\omega) + (1 - n)^2}} = 0.707
$$
This is a transcendental equation and cannot be solved algebraically in closed-form. However, you can **solve numerically** for $\omega_{3dB}$ for a given $n$.
---
### Step 4: Approximate Formula for 3 dB Frequency
For small $n$, an **approximate formula** for the normalized cutoff frequency (in radians/sample) is:
$$
\omega_{3dB} \approx n
$$
In terms of frequency in Hz (assuming a sample rate $f_s$):
$$
f_{3dB} \approx \frac{n \cdot f_s}{2\pi}
$$
---
### โ
Summary
* **Filter type**: First-order IIR low-pass
* **Filter equation**:
$$
Y_k = (1 - n) Y_{k-1} + n X_k
$$
* **3 dB point (approximate in Hz)**:
$$
f_{3dB} \approx \frac{n \cdot f_s}{2\pi}
$$
where $f_s$ is the sampling rate in Hz
Let me know your value of $n$ and the sampling rate if you want a specific 3 dB frequency calculated.
---
You're given a **discrete-time system** defined by the difference equation:
$$
y[n] = \alpha \cdot x[n] + (1 - \alpha) \cdot y[n - 1]
$$
This is a classic **first-order IIR low-pass filter**, just like in your previous question.
---
### ๐น Step 1: Take the Z-transform
Using the properties of the Z-transform (assuming zero initial conditions):
* $\mathcal{Z}\{y[n]\} = Y(z)$
* $\mathcal{Z}\{y[n - 1]\} = z^{-1} Y(z)$
* $\mathcal{Z}\{x[n]\} = X(z)$
Substitute into the difference equation:
$$
Y(z) = \alpha X(z) + (1 - \alpha) z^{-1} Y(z)
$$
---
### ๐น Step 2: Solve for the Transfer Function
Rearrange:
$$
Y(z) - (1 - \alpha) z^{-1} Y(z) = \alpha X(z)
$$
Factor $Y(z)$:
$$
Y(z) \left(1 - (1 - \alpha) z^{-1} \right) = \alpha X(z)
$$
$$
H(z) = \frac{Y(z)}{X(z)} = \frac{\alpha}{1 - (1 - \alpha) z^{-1}}
$$
---
### โ
Final Answer:
$$
\boxed{H(z) = \frac{\alpha}{1 - (1 - \alpha) z^{-1}}}
$$
This is the **transfer function** of the filter in the Z-domain.
Let me know if you want the frequency response, pole/zero plot, or time-domain behavior from this!
Powered by blists - more mailing lists