Sunday, September 17, 2023

How Does Qualcomm's Fingerprint Sensor Work?

Introduction

I recently came across a demonstration of the Samsung S22's fingerprint sensor while browsing used phones. Although it was challenging to find accurate information on how this technology works, I did eventually uncover details about its origins. This article outlines what I've learned.

My Motivation


Having previously worked on medical ultrasound imaging, I find the potential of a mass-produced 2D array of ultrasonic transducers particularly intriguing. Such an array could revolutionize low-cost 3D ultrasound imaging.
 

Link to the Initial Research on the Technology


Around 2015, Bernhard E. Boser's research group was instrumental in developing the piezoelectric micromachined transducer (PMUT). Yipeng Lu, one of the authors of the seminal 2016 paper [1] on this topic, joined Qualcomm as a senior engineer. Recent patents by Qualcomm include contributions from Kostadin Dimitrov Djordjev, Jessica Liu Strohmann, and Nicholas Ian Buchan, but this article focuses solely on information from the 2016 paper.

Additional evidence supporting the presence of PMUT devices in Qualcomm's 3D Sonic comes from a report by System Plus Consulting [2]. This report specifically mentions the use of PMUT technology. Furthermore, a YouTube video [3] provides a visual demonstration, showing the kinds of images achievable with a larger version of the sensor:

Construction of the Sensor


The PMUTs are MEMS devices bonded to a CMOS ASIC equipped with high-voltage (24V) transistors.

How Does the piezoelectric micromachined transducer  (PMUT) Work?


The core of a PMUT is an Aluminum Nitride (AlN) layer sandwiched between electrodes. During transmission, an applied voltage causes the AlN membrane to buckle, emitting an ultrasonic wave. When in reception mode, incoming pressure waves induce a charge across the transducer. The front side of the PMUT is coupled to the finger through a 250µm layer of silicone, while the backside is in a vacuum to prevent emission or losses towards the back.

Array Utilization for Imaging


The sensor comprises an array of 110 rows x 56 columns of PMUTs, arranged at a 43µm x 58µm pitch. This array achieves approximately 500 dpi resolution. Column-wise sequential readout is enabled by 56 analog demodulators. Transmit signals, created by exciting five adjacent columns, are time-delayed to focus the ultrasonic beam. The received signals are then processed to construct the image.

The algorithm employed for image construction is quite rudimentary. It essentially captures the envelope of the received ultrasonic signal at a predetermined time instant, without the use of more sophisticated image reconstruction techniques like beamforming or Fourier-based methods.

Conclusion

Pros

Qualcomm's ultrasonic fingerprint sensor stands as a remarkable engineering achievement. Not only can it capture high-resolution fingerprint images swiftly, but it also excels in challenging conditions like wet or oily surfaces and in complete darkness, thanks to its ultrasonic imaging capabilities. Moreover, its energy-efficient design is so optimized that the sensor can double as a power switch for the device, further enhancing its practicality.

Security Considerations

While Qualcomm claims the 3D imaging capabilities of their sensor enhance biometric security, I have some skepticism, particularly concerning the depth imaging. The employed reconstruction algorithm is fairly basic, which brings into question the sensor's resistance to spoofing techniques. This skepticism seems to be supported by existing evidence. Indeed, a brief search led to a report detailing a successful spoofing attack on a similar ultrasonic fingerprint sensor using a 3D-printed finger [4]. Given these factors, the actual security efficacy of Qualcomm's sensor remains an open question.

Future Applications and Hackability

Given its high-volume production and intricate engineering aimed at a specific problem, Qualcomm's sensor is a compelling candidate for other innovative applications. While the sensor is currently designed for fingerprint scanning, one could envision hacking the device to explore further into biological tissues, potentially repurposing it as an ultrasonic tomograph.

The present architecture, if sufficiently modified, could provide much-needed capabilities for 3D imaging in medical applications. Currently, the sensor focuses on a shallow layer of the skin to read fingerprints. However, with alterations in the excitation pulses and the readout strategy, the sensor might be capable of imaging deeper tissue structures.

To turn this into a reality, the sensor's readout would need to be modified to sample each PMUT at higher frequencies, enabling more sophisticated beamforming techniques for imaging. The challenge here would be in the high-speed, high-resolution data acquisition that proper beamforming would require.

Admittedly, such a modification would not be straightforward. These sensors are highly optimized to serve their primary function of fingerprint scanning. Yet, the concept of repurposing a mass-produced, sophisticated piece of hardware like this for medical imaging or other scientific applications is tantalizing. It would certainly require a deep dive into the sensor's architecture and capabilities, but the payoff could be monumental, offering a low-cost solution for more intricate imaging needs.

References

[1] Tang, Hao-Yen, et al. "3-D ultrasonic fingerprint sensor-on-a-chip." IEEE Journal of Solid-State Circuits 51.11 (2016): 2522-2533. https://ieeexplore.ieee.org/abstract/document/7579196
[2] System Plus Consulting Report https://s3.i-micronews.com/uploads/2019/07/SP19465-YOLE_Qualcomm-3D-Sonic-Sensor-Fingerprint_Sample.pdf
[3] YouTube Video https://youtu.be/JeTm5sd8ktg?t=143
[4] Spoofing attack https://www.digitalinformationworld.com/2019/04/samsung-galaxy-s10-ultrasonic-sensor-fingerprint.html

Time-Gating for 7 Frames with a Digital Micromirror Device

Introduction  

The paper titled "Diffraction-gated real-time ultrahigh-speed mapping photography" ([2]) presents a method for capturing seven distinct frames at an ultra-fast speed.

Method  

The study employs a Digital Micromirror Device (DMD), a MEMS-based technology featuring an array of tiny mirrors that can toggle between two orientations at high speeds. Placed in the back focal plane of an imaging system, the DMD produces seven diffraction orders, essentially creating seven copies of the input image.

All mirrors in the DMD array tilt synchronously. During transitions from an "all-off" to an "all-on" state, this synchronous tilt yields a dynamic phase profile. This results in the diffraction envelope sweeping through the seven diffraction orders.

Equation 1 outlines the DMD's diffraction pattern:




This equation describes the intensity of a point target observed in the intermediate image plane. Two sinc functions modulate the diffraction orders: one depends on the width of individual mirrors and the other on the width of the device. The time-dependent element here is the instantaneous tilt angle θb of the mirrors.

Note: A potential error could be the cos(mπ) term located outside the sum over m.

Performance metrics indicate a frame interval of 0.21 us ± 0.03 us, corresponding to 4.8 million frames per second.

Applications  

While capturing just seven consecutive frames may seem limited, there are intriguing applications. Given the short integration time, the method requires either high light power or multiple cycles of the DMD mirrors. Potential applications include:

  • Analyzing the ablation patterns of pulsed lasers
  • Investigating the spatial distribution of light modes in a moving multi-mode fiber
  • Studying transient changes in photonic integrated chips, such as superluminescent diodes or lasers with modulated gain sections

References  

- [1] AJD-4500 DMD Controller https://ajile.ca/ajd-4500/
- [2] Optica Paper https://opg.optica.org/optica/fulltext.cfm?uri=optica-10-9-1223&id=538060
- [3] Hacker News Discussion https://news.ycombinator.com/item?id=37523314

Sunday, September 6, 2020

Display copernicus sentinel 1 space packet headers as a table with gtkmm


I am working on a project to visualize the raw radar data of the Copernicus Sentinel 1 satellite.

The data comes in a binary format with header information. Each row in the following figure contains header information of one "space packet":

This source code parses the header information and renders the data as a table in a GTK TreeView:

 https://github.com/plops/cl-cpp-generator2/blob/b13e3afbb30a5958f8e2a6d45b35523f02d32fed/example/33_copernicus_gtk/source/vis_00_base.cpp

The column titles are quite long. In order to fit the table better on the screen I shorten the strings in the table header. The full column title is displayed as a tooltip.

 

I find it surprisingly difficult to express this in gtkmm.

 

Next I want to plot some of the data. I found a dataset that was acquired in stripmap mode and contains several good point spread functions (ships in water).



Sunday, August 16, 2020

Google Protocol Buffers for serial communication with a microcontroller


For a while now I was thinking about implementing a protobuf based binary protocol in the firmware of a microcontroller.

This would have the following advantages:

proto files as specification
parser generators for many languages (python, c)
versioning/backward compatibility
speed up transfer


As a proof of concept I implemented a single message that the microcontroller will send to the host computer using the following packet.
The packet starts with 5 "U" characters and ends with 5 "0xff" bytes:

0x55 0x55 0x55 0x55 0x55 <len_lsb> <len_msb> <payload_bytes...> 0xff 0xff 0xff 0xff 0xff


This preamble looks good in the logic analyzer and I think I can eventually use it for baudrate estimation.


A 16 bit packet length is included and the payload data is encoded using a google protocol buffer file:
https://github.com/plops/cl-cpp-generator2/blob/master/example/29_stm32nucleo/source/simple.proto


syntax = "proto2";
import "nanopb.proto";
message SimpleMessage {
required uint32 id = 1;
required uint32 timestamp = 2;
required uint32 phase = 3;
repeated int32 int32value = 4;
required int32 sample00 = 5;
...
required int32 sample59 = 64;
};





The packet encoder on the MCU is using https://github.com/nanopb/nanopb. It generates encoders and parsers that are compatible with google protocol buffers but the code is C instead of C++ and the code size is small.


https://github.com/plops/cl-cpp-generator2/blob/master/example/29_stm32nucleo/source/boilerplate/main.c



The packet is generated around line 524 (search for "SimpleMessage").


Initially I couldn't figure out how to fill a variable length array. That is why have samle00..sample59 variables. Later I learned how to store an array in int32value line 531, using callback the callback encode_int32.


The python code
https://github.com/plops/cl-cpp-generator2/blob/master/example/29_stm32nucleo/source2/run_00_uart.py

feeds all received bytes into a finite state machine that searches for the five "U" character preamble, parses the packet length and decodes the payload data with code that is autogenerated by google protobuf from simple.proto.

 

Received packets look like this after decoding:


id: 1431655765
timestamp: 4281899953 
phase: 16
int32value: 42
int32value: 43
int32value: 44
int32value: 45
int32value: 46
int32value: 47
int32value: 48
int32value: 49
int32value: 50
int32value: 51
sample00: 193
sample01: 193
...
sample52: 206
sample53: 1999
sample54: 1776
sample55: 300
sample56: 205
sample57: 196
sample58: 193
sample59: 190






The MCU code itself solves a toy problem. I generate output like this:
4095 0 0 4095 0 0 0 4095 0 0 0 ...
on the DAC and read it back with the ADC. Each sample of the ADC is integrated for 2.5cycles of the 80MHz system clock


I shift the ADC trigger relative to the DAC output clock with a PWM timer.


My goal was to investigate the influence of the DAC output buffer.



With buffer the ADC samples do not change much when the ADC acquires the data with a delay after the DAC has settled:

 
 
 
Without DAC buffer the ADC signal gets lower the longer the duration between DAC output instance and ADC acquisition trigger.
 

Sunday, July 12, 2020

ARPACK sparse eigenvalues and GPU

I am trying to learn how to find eigenvalues and eigenvectors of a sparse matrix. A good example problem are electronic orbitals of the hydrogen atom. This paper gives a good introduction:


https://www.mdpi.com/2218-2004/6/2/22/pdf
The structure of the matrix is like this:


A CUDA kernel that implements the matrix vector product looks like this: 

I use ARPACK++ with its reverse communication interface to compute the matrix vector products on the an RTX 2060 GPU.
 The results are similar to the benchmark results listed in the paper:
The radial component of the wavefunction of the ground state looks like this:


The source code is available on github:
 Note that the C++ and CUDA code is generated from Common Lisp source https://github.com/plops/cl-cpp-generator2/blob/master/example/27_sparse_eigen_hydrogen/gen00.lisp.

Sunday, May 5, 2019

Numerical derivative of analytic functions

I  recently learned about a neat trick to compute the derivative of an analytic function.

Others [1] have described it better than I could. So I just keep this here as a reminder.


[1] https://blogs.mathworks.com/cleve/2013/10/14/complex-step-differentiation/


Exact representation of floating point constants

C99 allows to represent the significand of floating a point value in a hexadecimal notation [2]. This format captures the exact number in a finite number of characters.


I plan to use this with my C code generator [4] to represent unique twiddle factors of the fast Fourier transform [5].

Here is Common Lisp code that will generate the C string to represent a single float:


(defun single-float-to-c-hex-string (f)
  (declare (type (single-float 0) f))
  (multiple-value-bind (a b c) (integer-decode-float f)
  (let ((significand (ash a 1)))
    (format nil "0x~x.~xp~d"
        (ldb (byte 4 (* 6 4)) significand)
        (ldb (byte (* 6 4) 0) significand)
       (+ 23 b)))))


(single-float-to-c-hex-string .1s0) ;; => "0x1.99999Ap-4"



[1] http://clhs.lisp.se/Body/f_dec_fl.htm    decode-float float => significand, exponent, sign
[2] https://www.exploringbinary.com/hexadecimal-floating-point-constants/ examples of c hex notation
[3] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf page 57, parsing
[4] https://github.com/plops/cl-cpp-generator
[5] https://github.com/plops/cl-gen-cuda-try/blob/master/gen-simd.lisp